Add your own alternative version
Stats
135K views 3.4K downloads 39 bookmarked
Posted
11 Jul 2002

Comments and Discussions


I like the design of these controls. What would be the steps for transforming this control into an ActiveX object?





I have added the following after the For i = Minimum To Maximum > "step smallscale" or "step largescale".
This seems to have fixed the tick marks fault. (see below)
' Draw small and large scale
Dim i As Integer = Minimum
If (Me._ShowSmallScale) Then
For i = Minimum To Maximum step smallscale
gOffScreen.DrawLine(New Pen(Me.ForeColor), getMarkerPoint(0, i), getMarkerPoint(3, i))
Next
End If
If (Me._ShowLargeScale) Then
For i = Minimum To Maximum step largescale
gOffScreen.DrawLine(New Pen(Me.ForeColor), getMarkerPoint(0, i), getMarkerPoint(5, i))
Next
End If
Matthew Lewis





Hi
First of all i would like to thank you for this great control.
I would like to modify it to make a full 360 degree rotation without
the gap. Can anybody help me with this one?
Thank you. Keep up the great work





I'm trying to use this in VB.NET 2005 but I'm getting some errors when I drag this control onto a form:
'KnobControl' is ambiguous in the namespace 'KnobControl'
'CUtility' is ambiguous in the namespace 'KnobControl'.
Any help would be appreciated. This is a great control.
I also have a feature request if you choose to update this: Could there be an option to turn off the automatic scaling of the tick marks so I could choose the amount? My application uses MIDI and the maximum value is usually 127 (sometimes more) and a lot of tick marks doesn't look very nice. I'd like an option other than turning them off completely.
Thanks!





Maybe it would be great to include in onPaint() these lines of code (after g.DrawImage(OffScreenImage,0,0);)
Font fnt = new Font(FontFamily.GenericSansSerif, 10, FontStyle.Regular);
g.DrawString(this.Value.ToString(), fnt, new SolidBrush(Color.FromArgb(80, 80, 80)), new PointF((rKnob.X + rKnob.Width / 2)  (g.MeasureString(this.Value.ToString(), fnt).Width / 2), (rKnob.Y + rKnob.Height / 2)));





Where can I find the C# version?
Thanks,
John Long






Thanks,
John
Thanks,
John Long
Seattle, WA USA





Can you post me original C# code?
Link you've provided is now dead.
Thanks in advance
Michał Bryłka





There is an issue with your know control... Arithmetic operation resulted in an overflow.
It is easily reproducable... Click on the little dot to change the value of one of the control in your example. Now, go with the mouse still clicked, go far away to the right with you mouse. Now, come back on the button and try to go in the middle of it. BOOOOOOOOOOOOM...
Just tested quickly...
Regards,
Francois
Thank God it's Friday!!





Replace getValueFromPosition() with the following to correct this bug:
Private Function getValueFromPosition(ByVal p As Point) As Integer
Dim degree As Double = 0.0
Dim v As Integer = 0
Try
If (p.X <= pKnob.X) Then
degree = (pKnob.Y  p.Y) / (pKnob.X  p.X)
degree = Math.Atan(degree)
degree = (degree) * (180 / Math.PI) + 45
v = (degree * (Me.Maximum  Me.Minimum) / 270)
ElseIf (p.X > pKnob.X) Then
degree = (p.Y  pKnob.Y) / (p.X  pKnob.X)
degree = Math.Atan(degree)
degree = 225 + (degree) * (180 / Math.PI)
v = (degree * (Me.Maximum  Me.Minimum) / 270)
End If
Catch
End Try
If (v > Maximum) Then v = Maximum
If (v < Minimum) Then v = Minimum
Return v
End Function





The problem seems to be a dividebyzero problem.
Below, the original function accounted for the case of
p.X <= pKnob.X with degree = (pKnob.Y  p.Y) / (pKnob.X  p.X).
The problem is when p.X = pKnob.X then that reduces to (pKnob.Y  p.Y) / 0.
Here is part of the original code. Fix follows below that.
Private Function getValueFromPosition(ByVal p As Point) As Integer
Dim degree As Double = 0.0
Dim v As Integer = 0
If (p.X <= pKnob.X) Then
degree = (pKnob.Y  p.Y) / (pKnob.X  p.X)
degree = Math.Atan(degree)
degree = (degree) * (180 / Math.PI) + 45
v = (degree * (Me.Maximum  Me.Minimum) / 270)
ElseIf (p.X > pKnob.X) Then
degree = (p.Y  pKnob.Y) / (p.X  pKnob.X)
degree = Math.Atan(degree)
degree = 225 + (degree) * (180 / Math.PI)
v = (degree * (Me.Maximum  Me.Minimum) / 270)
End If
If (v > Maximum) Then v = Maximum
If (v < Minimum) Then v = Minimum
Return v
End Function
The fix:
Since p.X = pKnob.X when the mouse is exactly half way horizontally across
the knob. It seems only fair to make the value returned half the range of
the knob's scale. Even in the nogo zone at the bottom of the knob, the
original version still snaps to full scale or minimum as you move across the
bottom area. The adjusted function below snaps the value to half scale right
on the middle pixel of the control and avoids the dividebyzero problem.
Private Function getValueFromPosition(ByVal p As Point) As Integer
Dim degree As Double = 0.0
Dim v As Integer = 0
If (p.X < pKnob.X) Then
degree = (pKnob.Y  p.Y) / (pKnob.X  p.X)
degree = Math.Atan(degree)
degree = (degree) * (180 / Math.PI) + 45
v = (degree * (Me.Maximum  Me.Minimum) / 270)
ElseIf (p.X > pKnob.X) Then
degree = (p.Y  pKnob.Y) / (p.X  pKnob.X)
degree = Math.Atan(degree)
degree = 225 + (degree) * (180 / Math.PI)
v = (degree * (Me.Maximum  Me.Minimum) / 270)
ElseIf (p.X = pKnob.X) Then
v = (Me.Maximum + Me.Minimum) / 2
End If
If (v > Maximum) Then v = Maximum
If (v < Minimum) Then v = Minimum
Return v
End Function
To fix, open the KnobContol.vb code and alter as above. Rebuild KnobControl,
NOT the solution, then Close the project. To see the effect, open up
TestKnobControl and in the solution Explorer, click the References node to
expand it. Rightclick on KnobControl, click Delete, to remove the
reference. Rightclick References and select Add Reference. In the Add
Reference window that opens, click Browse and navigate to where the
KnobControl project is and go to the bin directory under it. Select
KnobControl.dll and click Open. Back in the Add Reference window, click OK.
Now run the updated TestKnobControl project.
Mitchell Day
mitchell_day@hotmail.com





Thanks for the great article! I'm trying to teach myself how to create my own controls, and this has been a great help. I did notice a couple of things, though. Firstly, when setting ShowLargeScale = True, it redraws all of the ticks, instead of only the large scale ticks. I think the OnPaint event needs to be updated from:
If (Me._ShowLargeScale) Then
For i = Minimum To Maximum
gOffScreen.DrawLine(New Pen(Me.ForeColor), getMarkerPoint(0, i), getMarkerPoint(8, i))
Next
End If
To:
If (Me._ShowLargeScale) Then
For i = Minimum To Maximum
If i Mod _LargeChange = 0 Then
gOffScreen.DrawLine(New Pen(Me.ForeColor), getMarkerPoint(0, i), getMarkerPoint(8, i))
End If
Next
End If
Does this seem right? Also, I think that when changing the Min & Max properties, it should call a refresh.
I was trying to extend this a little bit and have the Tick Value displayed as well (kinda like an Amp knob). I added a ShowNumber property, and in the OnPaint event I put the following code:
If (Me._ShowNumbers) Then
For i = Minimum To Maximum
If Me._ShowLargeScale = True Then
If i Mod _LargeChange = 0 Then
gOffScreen.DrawString(i.ToString(), Me.Font, bNumbers, getTextPoint(i).X, getTextPoint(i).Y)
End If
Else
gOffScreen.DrawString(i.ToString(), Me.Font, bNumbers, getTextPoint(i).X, getTextPoint(i).Y)
End If
'gOffScreen.DrawLine(New Pen(Me.ForeColor), getMarkerPoint(0, i), getMarkerPoint(5, i))
Next
End If
The getTextPoint(TickNumber) function is as follows:
Private Function getTextPoint(ByVal Value As Integer) As Point
Dim degree As Double = 270 * Value / (Me.Maximum  Me.Minimum)
Dim center As New Point((rKnob.Height / 2) + rKnob.X, (rKnob.Width / 2) + rKnob.Y)
degree = (degree + 135) * (Math.PI / 180)
Dim radius As Integer = (rKnob.Height / 2) + 4
center.Offset((Math.Cos(degree) * radius), (Math.Sin(degree) * radius))
If Math.Sin(degree) < 0 Then
center.Offset(0, Math.Sin(degree) * 15)
End If
If Math.Cos(degree) < 0 Then
center.Offset(Math.Cos(degree) * 15, 0)
End If
Return center
End Function
The tough part is getting the text to line up with the ticks. I'm still off a bit, but this is pretty close. Now you can make a knob control for an Amp that has an 11 on it...
Again, thanks for the great article...
Josh
If at first you don't succeed, blame {insert software company here}...






General News Suggestion Question Bug Answer Joke Praise Rant Admin Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

