# VBForums CodeBank > CodeBank - Visual Basic .NET >  [WIP] Double TrackBar

## NickThissen

Hi,

I needed a double TrackBar control for my project (one where the user can set a minimum and maximum value, for example) so I decided to create my own.

It basically does anything the real TrackBar does as well, except different track styles and vertical orientation (still in my TODO list...)

Screenshot:


It works just like the normal TrackBar, the user can grab one of the handles and move it to a different value. My code uses the TrackBarRenderer class to draw the ticks and the grab handles so it should look just like the ordinary TrackBar control, whatever system theme you are using.


*Update 1*:
Implemented some changes:
Events ValueChanged, LeftValueChanged and RightValueChanged, raised when the position of a thumb changes. ValueChanged is raised for either thumb, while LeftValueChanged and RightValueChanged obviously are only raised when the corresponding thumb position changes.Scrolling the mousewheel when a thumb is selected changes the position of that thumb, similar to the normal TrackBar control.SelectedThumb property that returns the thumb (Left or Right) that was focused (or 'used') last. This is used by the scrolling support to determine which thumb to scroll.Bugfix: thumbs can no longer move to the same position to avoid not being able to drag them anymore.



*Important:* I am also using a custom designer so you can move the handles during design-time as well as during run-time. Because of this you will need to add a reference to *System.Design* in order to compile the code.

*NEW:*
I've now also uploaded a version without the designer, so you no longer have to reference System.Design. This allows you to use the Client Profile frameworks (which don't include System.Design). If you don't need or don't want the design-time dragging, you can use the 'No designer' version.



Here's a few things (that I can think of) that this DoubleTrackBar control doesn't have (yet), which the normal TrackBar does have:
Multiple styles (such as double tickbars, horizontal vs vertical layout, etc)Probably more...

As I said, I might implement that at a later time, so this is still a work in progress.

Enjoy!

----------


## bezkintos

Hi Nick! 

Great work with double trackbar! 

I have searched for this for several weeks and yours solution is the only VB solution that actually works. I was wondering if you maybe continued to work on double trackbar and implement scrolling support? 

Also there is a small bug in your trackbar and I was hoping that you might have solution for it: when two handles overlaps, always the left one goes on top of the right one. The problem occurs when both handles are dragged to value 0. Then they are stucked there because you can't grab the right one to drag it to the right. Please post if you have solution for this.

Thanks!

----------


## NickThissen

> Hi Nick! 
> 
> Great work with double trackbar! 
> 
> I have searched for this for several weeks and yours solution is the only VB solution that actually works. I was wondering if you maybe continued to work on double trackbar and implement scrolling support? 
> 
> Also there is a small bug in your trackbar and I was hoping that you might have solution for it: when two handles overlaps, always the left one goes on top of the right one. The problem occurs when both handles are dragged to value 0. Then they are stucked there because you can't grab the right one to drag it to the right. Please post if you have solution for this.
> 
> Thanks!


Hi. I have not worked on this any further because I didn't need it after all. I'll take a look this evening if I can implement your ideas and fix that bug, should be an easy fix.

----------


## NickThissen

I've updated the first post with the changes.

Your bug has been fixed. You can no longer drag thumbs on top of eachother so the bug can no longer occur. 

Scrolling works now, and the thumb you 'used' last will move when you scroll.

Some other minor fixes were also applied, and I added a version without the design-time support. The ability to move the thumbs during design-time is usually pretty useless anyway and for most people probably isn't worth having to reference System.Design, because this means you have to use the full 3.5 or 4.0 framework instead of the Client Profile versions which are smaller in size.
In short, use the No designer version if you don't need the designer option.

----------


## bezkintos

Hi Nick!

Thanks for quick respond and new release!  :Wink: 
Bug fix works great!

There is something strange with scrolling. You said "thumb you 'used' last will move when you scroll". If by "used" you thought grabing the thumb and moving it,  it actually doesn't work like that. First you have to select a thumb by clicking somewhere near it (but not on it), and it stays selected until you click somewhere near the other thumb (also, not on it but somewhere near it). So if you don't click next to the thumb first, but grab it directly and move it,  it won't be selected and the other thumb will move if you scroll. It took me 20 minutes to figure this out  :Smilie: 
I have VS2010 and opened a fresh new project and added you code so I guess nothing I did could interfere on scrolling behaviour. 

Another thing is mousewheel vs scroll. I think you implemented mousewheel support, not scrolling.

If you do this with standard trackbar:



```
    Private Sub TrackBar1_Scroll(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TrackBar1.Scroll

        Label1.Text = TrackBar1.Value

    End Sub
```

then, Label1.Text value changes as you scroll, but also in the same way it changes if you grab thumb and move it using left mouse button (value changes like when you scroll, not like when you use mouseup or mousedown event).

But if you do this:



```
    Private Sub TrackBar1_MouseWheel(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TrackBar1.MouseWheel

        Label1.Text = TrackBar1.Value

    End Sub
```

then Label1.Text value changes only as you scroll using mouse wheel.


Please, don't think I'm ungrateful and preaching - this was only my observations. I still think you did a great job and that you should sell this code to Microsoft so that they finally implement double trackbar in next Visual Studio  :Wink:

----------


## NickThissen

Oops, I knew I forgot something  :Smilie:  I forgot to set the selected thumb when you move it directly. Will fix.
*EDIT*: Fixed  :Smilie: 


As for scrolling, I'm not sure what you mean. Maybe I misunderstand the scrolling support of the normal TrackBar (I have only used it very sparingly), but I understood your feature request as being able to scroll your mouse wheel which would move the thumb. It does that correctly, right?

As far as I know, the Scroll event of the normal TrackBar is raised when the value changes. I am a little stubborn in regards to naming and I named that event ValueChanged (as well as LeftValueChanged and RightValueChanged). Perhaps the Scroll event does more than I'm aware of, but if not, try using the ValueChanged event to update your label.

----------


## bezkintos

Hi Nick!

You are a freaking genius! If you ever decide to become president of some country, tell me which so I can take citizenship and vote for you!  :Wink: 

Your double trackbar now works like crazy!
And using the ValueChanged event to update my label also works!

Thank you again and to pay my gratitude here is a virtual beer for you! Enjoy!  :Big Grin: 
http://static.nacional.hr/img/2500ca...1b_700x550.jpg

----------


## NickThissen

Glad you found use for it, and thanks for the beer  :big yellow:

----------


## bezkintos

Hi Nick!

Me again  :Smilie: 

It's been a month now since I'm using your doubletrackbar and still I'm very satisfied.

This time I have just a small question and before I ask other people I came to ask you - *"The Creator"*. 

Because you have used VisualStyles in doubletrackbar it doesn't work if you switch Windows XP style to Windows Classic style. I found a function that checks if Visual Styles are enabled, and if not, I can use message box to notify users to switch back to Windows XP style. 
Still, my question is: by your knowledge, is it possible somehow to temporary enable Visual Styles under Windows Classic (don't know if this makes any sence) from within application so that your doubletrackbar would work?

----------


## NickThissen

I don't have a lot of time to look at it now, but after scanning through this it sounds like maybe you need to _disable_ the visual styles (from within your application, not my control) when they are using the classic style.
http://msdn.microsoft.com/en-us/library/ms171733.aspx

As far as I understand the renderers will then use the classic style:



> If visual styles are enabled, then the class members will draw the related control with visual styles; if visual styles are disabled, then the class members will draw the control in the classic Windows style.


Can you try that?

----------


## bezkintos

Hi Nick,
thanks for quick reply!

I tried you suggestion (to disable visual styles) and it didn't work. Also, immediately after the sentence you quoted it says that it refers only to ButtonRenderer, CheckBoxRenderer, GroupBoxRenderer and RadioButtonRenderer.

I thought you might know how to solve this with no extra effort, but don't bother, you already did a great job with doubletrackbar, no need to spend any more time on it. I will continue for a while to search for a solution and post on some other forums and if I find anything, will report here.

Thanks again.
Bye!

----------


## NickThissen

Hm, didn't see that. As far as I can see, the only solution is to check if visual styles are enabled (TrackBarRenderer.IsSupported), and if they are not, draw the whole thing yourself using GDI+. I've no clue how a trackbar looks in the classic theme but the classic theme is usually not very hard to replicate in GDI+ so that should work.

----------


## gezepi

For a project I'm working on I needed a Trackbar with 3 Thumbs so I modified NickThissen's code for the DoubleTrackBar.  It's not nearly as polished as the original but if anybody else needs it here it is.

----------


## while1

Nick,
Thank you for this solution.  Embarrassing question:  how do I use it?
When I add DoubleTrackBar.vb to my project via right-click "Include In Project", add reference to System.Design, the control does not show up in my toolbox.
What am I overlooking?  How do I add the control to my Form and start using it?
Thank you in advance.

----------


## NickThissen

Did you build the solution successfully (meaning: there were no errors)?

----------


## while1

Yes it builds fine.  0 errors.  
Aha, a new group has appeared in my Toolbox:  "[ProjName] Components" and it has DoubleTrackBar within it.
I did not know one had to build the project first in order to see the 3rd party component get added to the toolbox.  I can now successfully add it to my form.
Thank you!

----------


## NickThissen

Yes, building is the process of compiling the code in your solution and creating the executable (or dll). The toolbox checks in your executable (or dll) for types that inherit Component and shows them in the toolbox. If you did not build your solution, the DoubleTrackBar type was not compiled yet so the toolbox cannot see it  :Smilie:

----------


## bezkintos

Hi Nick,

few days ago I have noticed a little different behavior of yours DoubleTrackbar compared with the regular Trackbar. The problem I noticed is that DoubleTrackBar1.ValueChanged event always fires when you run application (before you even have touched DoubleTrackbar) - and it fires twice. You can easily check this using this code example:



```
Public Class Form1

    Private Sub DoubleTrackBar1_ValueChanged(sender As System.Object, e As System.EventArgs) _
        Handles DoubleTrackBar1.ValueChanged

        MsgBox("bla")

    End Sub

End Class
```

Do you maybe have idea what is causing this behavior? Is there some quick and easy solution?
Please, believe me, I'm not lazy, I tried to check your code by myself, but I don't understand many things in there - I just started with Visual Basic (with programming in general) 5-6 month ago...

Thanks!

----------


## NickThissen

It probably fires when the designer is setting the initial value in the InitializeComponent method. I might be able to prevent that from within the control, but you can fix it too by adding the event handler in code, after initialization. Instead of choosing the event in the designer you use AddHandler to add it in the form constructor or load event. The same is often done with checkboxes and such, where you get the same problem. I can't give you any code right now since I'm typing this on my phone, but you can do a search for AddHandler...

----------


## bezkintos

Hi Nick,

I think I understood your suggestion. I did this and now ValueChanged event doesn't fire until you actually change the value on DoubleTrackbar:



```
Public Class Form1

    Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load

        AddHandler DoubleTrackBar1.ValueChanged, AddressOf DoubleTrackBar1_ValueChangedHandler

    End Sub

    Private Sub DoubleTrackBar1_ValueChangedHandler(sender As System.Object, e As System.EventArgs)

        MsgBox("bla")

    End Sub

End Class
```


Thanks again!

----------


## jerry chi

Hi Nick,

Thank you for your double thumb trackbar! 
I'm a vb beginner from hongkong. i added the double trackbar to my project.
but i changed Orientation to Vertical or Horizontal, it doesn't work.
could you give me some suggest? how to modify the code? need your reply, Tks.
My develop Environment: VS2010 .net4.0

Cheers
jerry

----------


## jerry chi

Hi Nick,

Thank you for your double thumb trackbar! 
I'm a vb beginner from hongkong. i added the double trackbar to my project.
but i changed Orientation to Vertical or Horizontal, it doesn't work.
could you give me some suggest? how to modify the code? need your reply, Tks.
My develop Environment: VS2010 .net4.0

Cheers
jerry




> Hi,
> 
> I needed a double TrackBar control for my project (one where the user can set a minimum and maximum value, for example) so I decided to create my own.
> 
> It basically does anything the real TrackBar does as well, except different track styles and vertical orientation (still in my TODO list...)
> 
> Screenshot:
> 
> 
> ...

----------


## NickThissen

I did not add vertical orientation. I was planning to do that but I didn't need it so it wasn't a priority. It shouldn't be too hard though, you'll basically have to take a look at the code that draws the components (the track bar, the ticks, the thumbs) and rotate that 90 degrees. I think I'm using TrackBarRenderer to render everything, it probably has methods to draw in vertical orientation too.

----------


## jerry chi

hi nick
do you implement this feature recently if you have time?
Im looking forward to see.




> I did not add vertical orientation. I was planning to do that but I didn't need it so it wasn't a priority. It shouldn't be too hard though, you'll basically have to take a look at the code that draws the components (the track bar, the ticks, the thumbs) and rotate that 90 degrees. I think I'm using TrackBarRenderer to render everything, it probably has methods to draw in vertical orientation too.

----------


## Nunny

For those that stumble across this and find that it doesn't work with Classic theme and really need it to.
Here is the solution that works and will get you started:

Replace/Edit/Add this stuff where appropriate. Thanks to OP!

Note: Kinda new the VB.net so might have done some dodgy stuff with the event handling...



```

    Private Function GetThumbRectangle(ByVal relativeValue As Double, ByVal g As Graphics) As Rectangle

        Dim Size As Size
        If Application.RenderWithVisualStyles Then
            Size = TrackBarRenderer.GetBottomPointingThumbSize(g, VisualStyles.TrackBarThumbState.Normal)
        Else
            Size = New Size(11, 19) 'This is the size that TrackBarRenderer returns when themes are on
        End If

        Dim border = CInt(Size.Width / 2)
        Dim w = Me.GetTrackRectangle(border).Width
        Dim X = CInt(Math.Abs(Me.Minimum) / (Me.Maximum - Me.Minimum) * w + relativeValue * w)
        Dim Y = CInt((Me.Height - Size.Height) / 2) - 7

        Return New Rectangle(New Point(X, Y), Size)
    End Function

    Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
        MyBase.OnPaint(e)

        Dim thumbSize = Me.GetThumbRectangle(0, e.Graphics).Size
        Dim trackRect = Me.GetTrackRectangle(CInt(thumbSize.Width / 2))
        Dim ticksRect = trackRect : ticksRect.Offset(0, 15)

        If Application.RenderWithVisualStyles Then
            TrackBarRenderer.DrawVerticalTrack(e.Graphics, trackRect)
            TrackBarRenderer.DrawHorizontalTicks(e.Graphics, ticksRect, Me.Maximum - Me.Minimum + 1, VisualStyles.EdgeStyle.Etched)
            TrackBarRenderer.DrawBottomPointingThumb(e.Graphics, Me.GetLeftThumbRectangle(e.Graphics), leftThumbState)
            TrackBarRenderer.DrawBottomPointingThumb(e.Graphics, Me.GetRightThumbRectangle(e.Graphics), rightThumbState)
        Else
            ControlPaint.DrawBorder(e.Graphics, trackRect, Color.Gray, ButtonBorderStyle.Inset)

            Dim TickNum As Integer = Maximum - Minimum + 1
            Dim TickSpace As Double = ticksRect.Width / TickNum
            For i As Integer = 0 To TickNum
                Dim tickRect As New Rectangle(ticksRect.X + i * TickSpace, ticksRect.Y, 2, ticksRect.Height)
                ControlPaint.DrawBorder(e.Graphics, tickRect, Color.Gray, ButtonBorderStyle.Solid)
            Next

            ControlPaint.DrawButton(e.Graphics, Me.GetLeftThumbRectangle(e.Graphics), GetButtonStateFromThumbState(leftThumbState))
            ControlPaint.DrawButton(e.Graphics, Me.GetRightThumbRectangle(e.Graphics), GetButtonStateFromThumbState(rightThumbState))
        End If
    End Sub

    Private Function GetButtonStateFromThumbState(ThumbState As VisualStyles.TrackBarThumbState) As ButtonState
        Select Case ThumbState
            Case VisualStyles.TrackBarThumbState.Disabled
                GetButtonStateFromThumbState = ButtonState.Inactive
            Case VisualStyles.TrackBarThumbState.Hot
                If Me.Focused Then
                    GetButtonStateFromThumbState = ButtonState.Checked
                Else
                    GetButtonStateFromThumbState = ButtonState.Normal
                End If
            Case VisualStyles.TrackBarThumbState.Normal
                GetButtonStateFromThumbState = ButtonState.Normal
            Case VisualStyles.TrackBarThumbState.Pressed
                GetButtonStateFromThumbState = ButtonState.Pushed
            Case Else
                GetButtonStateFromThumbState = ButtonState.Normal
        End Select
    End Function

    Private Sub OnLoseFocus(sender As Object, e As System.EventArgs) Handles MyBase.LostFocus
        Invalidate() ' need this to force repaint on lose focus to change thumb state for classic theme
        RaiseEvent LostFocus(sender, e)
    End Sub

Shadows Event LostFocus As EventHandler
```

----------


## Nunny

Good on me posting before testing properly.
Post is waiting on moderator approval so cannot edit original reply...
It has a bug (trackbar was drawing too many ticks...) and I cannot edit my post
Here is fixed code



```
    Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
        MyBase.OnPaint(e)

        Dim thumbSize = Me.GetThumbRectangle(0, e.Graphics).Size
        Dim trackRect = Me.GetTrackRectangle(CInt(thumbSize.Width / 2))
        Dim ticksRect = trackRect : ticksRect.Offset(0, 15)

        If Application.RenderWithVisualStyles Then
            TrackBarRenderer.DrawVerticalTrack(e.Graphics, trackRect)
            TrackBarRenderer.DrawHorizontalTicks(e.Graphics, ticksRect, Me.Maximum - Me.Minimum + 1, VisualStyles.EdgeStyle.Etched)
            TrackBarRenderer.DrawBottomPointingThumb(e.Graphics, Me.GetLeftThumbRectangle(e.Graphics), leftThumbState)
            TrackBarRenderer.DrawBottomPointingThumb(e.Graphics, Me.GetRightThumbRectangle(e.Graphics), rightThumbState)
        Else
            ControlPaint.DrawBorder(e.Graphics, trackRect, Color.Gray, ButtonBorderStyle.Inset)

            Dim TickNum As Integer = Maximum - Minimum
            If TickNum > 0 Then
                Dim TickSpace As Double = ticksRect.Width / TickNum
                For i As Integer = 0 To TickNum
                    Dim tickRect As New Rectangle(ticksRect.X + i * TickSpace, ticksRect.Y, 2, ticksRect.Height)
                    ControlPaint.DrawBorder(e.Graphics, tickRect, Color.Gray, ButtonBorderStyle.Solid)
                Next
            End If
            ControlPaint.DrawButton(e.Graphics, Me.GetLeftThumbRectangle(e.Graphics), GetButtonStateFromThumbState(leftThumbState))
            ControlPaint.DrawButton(e.Graphics, Me.GetRightThumbRectangle(e.Graphics), GetButtonStateFromThumbState(rightThumbState))
        End If
    End Sub
```

----------


## krishanudey99

Hi everyone, I found this article few hours ago. I needed this control in c#. So I converted it. but after convertion the control is having issue with the "Click-n-Drag" feature. When I click on any thumb, and drag it, ti doesn't work. rest of the features are working just fine. This feature is working perfectly in the VB version. So I think there is some bug in my C# code, but not able to find it out. I'm attaching my c# version

DoubleTrackBar.cs

----------


## corori

rewrite line 404

var offset = Convert.ToInt32(e.Location.X / (this.Width) * (this.Maximum - this.Minimum));

into

var offset = (this.Maximum - this.Minimum) * e.Location.X;    offset = (int)(offset / (float)this.Width);

sorry my poor English :Frown:

----------


## gmillerok1

Ok, if he was embarrassed, I'm doubly so, because even though I've searched everywhere, I can't figure out how to install the vb file in the tool bar.

Can someone help me in that regard? I need a two arrow slider just like this for an app I have.

Thanks in advance,
Gerald




> Did you build the solution successfully (meaning: there were no errors)?

----------


## Geosuite

Hi, Nick,

I'm using VB Express 2010. I need to do exactly the same thing as you posted. Unfortunately I can't use your code because of the form design. Can you post the code for entire project or give suggestions? I'm in a very rush situation. It will be highly appreciated if you can also send your reply to soft4me@hotmail.com.

Thank you so much!  





> Hi,
> 
> I needed a double TrackBar control for my project (one where the user can set a minimum and maximum value, for example) so I decided to create my own.
> 
> It basically does anything the real TrackBar does as well, except different track styles and vertical orientation (still in my TODO list...)
> 
> Screenshot:
> 
> 
> ...

----------


## Geosuite

Hi, Nunny,

I'm not a professional programmer but I really need to add this "doubletrackbar" control to my program. I have difficulty to call your code from my "form". Could you provide some more details? Can you post a VB project? I'm suing VB 2010 Express.

Thank you very much.

----------


## AbdlrhmanShehata

> Hi,
> 
> I needed a double TrackBar control for my project (one where the user can set a minimum and maximum value, for example) so I decided to create my own.
> 
> It basically does anything the real TrackBar does as well, except different track styles and vertical orientation (still in my TODO list...)
> 
> Screenshot:
> 
> 
> ...


Thanks a lot sir for this article ,  i will review the control and tell you if there are any comments or recommendations .
Good Luck : )

----------


## JuggaloBrotha

> Hi, Nunny,
> 
> I'm not a professional programmer but I really need to add this "doubletrackbar" control to my program. I have difficulty to call your code from my "form". Could you provide some more details? Can you post a VB project? I'm suing VB 2010 Express.
> 
> Thank you very much.


There's really nothing to this, just use the "Add Existing" to add the "DoubleTrackBar.vb" file to your project.  Change the Target Framework from ".Net 4 Client Profile" to ".Net 4", then add the reference to "System.Design", compile the project then add the DoubleTrackBar to your form from the ToolBox.

----------


## Geosuite

> There's really nothing to this, just use the "Add Existing" to add the "DoubleTrackBar.vb" file to your project.  Change the Target Framework from ".Net 4 Client Profile" to ".Net 4", then add the reference to "System.Design", compile the project then add the DoubleTrackBar to your form from the ToolBox.


Thank you, @JuggaloBrotha. It works now

----------

