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!
Last edited by NickThissen; Aug 24th, 2011 at 05:45 PM.
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.
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.
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.
Thanks for quick respond and new release!
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
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:
Code:
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:
Code:
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
Oops, I knew I forgot something I forgot to set the selected thumb when you move it directly. Will fix. EDIT: Fixed
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.
Last edited by NickThissen; Aug 24th, 2011 at 05:05 PM.
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?
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.
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.
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.
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.
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.
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!
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
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:
Code:
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...
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...
I think I understood your suggestion. I did this and now ValueChanged event doesn't fire until you actually change the value on DoubleTrackbar:
Code:
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
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
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
Originally Posted by 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.
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.
hi nick
do you implement this feature recently if you have time?
Im looking forward to see.
Originally Posted by 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.
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...
Code:
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
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
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
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
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!
Originally Posted by 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.
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.
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!
Thanks a lot sir for this article , i will review the control and tell you if there are any comments or recommendations .
Good Luck : )
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.
Currently using VS 2015 Enterprise on Win10 Enterprise x64.
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.