Add your own alternative version
Stats
132.7K views 3.1K 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.

