这个是旋钮控件,用于调整数值。
其中旋钮的把手的形状、大小都是可以调整的。你也可以不显示把手。
那个小红点也是可以选择是否显示的。
旋钮的旋转范围也是可以调整的。
此外就是,旋钮的刻度的显示密度也是可调的。
为了保证画风不和Windows界面冲突,绘制旋钮用的颜色都是取自系统颜色(比如按钮表面、按钮暗阴影、按钮亮阴影等颜色)。 [Visual Basic] 纯文本查看 复制代码 002 | Begin VB.UserControl Knob |
010 | Begin VB.PictureBox picKnob |
012 | AutoRedraw = -1 'True |
021 | Begin VB.PictureBox picBase |
022 | AutoRedraw = -1 'True |
023 | BorderStyle = 0 'None |
036 | Attribute VB_Name = "Knob" |
037 | Attribute VB_GlobalNameSpace = False |
038 | Attribute VB_Creatable = True |
039 | Attribute VB_PredeclaredId = False |
040 | Attribute VB_Exposed = False |
041 | '============================================================================== |
044 | '版权所有 (C) 2013-2015 技术宅的结界 |
046 | '------------------------------------------------------------------------------ |
049 | Private Declare Function GetSysColor Lib "user32" ( ByVal nIndex As Long ) As Long |
051 | Private Const Knob_PI As Double = 3.14159265358979 |
052 | Private m_Rad As Double |
054 | Private m_Value As Long |
055 | Private m_Steps As Long |
056 | Private m_MaxAng As Double |
057 | Private m_MinAng As Double |
058 | Private m_MouseDown As Boolean |
059 | Private m_MouseAngle As Double |
060 | Private m_BaseRad As Double |
061 | Private m_HandleRad As Double |
062 | Private m_DrawGrad As Boolean |
063 | Private m_DrawPoint As Boolean |
064 | Private m_DrawRaisedHandle As Boolean |
065 | Private m_RaisedHandleWidth1 As Double |
066 | Private m_RaisedHandleWidth2 As Double |
069 | Attribute Click.VB_Description = "Triggerd when clicked." |
070 | Attribute Click.VB_UserMemId = -600 |
072 | Attribute DblClick.VB_Description = "Triggerd when double clicked." |
073 | Attribute DblClick.VB_UserMemId = -601 |
074 | Event Change( ByVal OldValue As Long , ByVal NewValue As Long ) |
075 | Attribute Change.VB_Description = "Triggerd when the value was changed." |
076 | Event MouseDown(Button As Integer , Shift As Integer , X As Single , Y As Single ) |
077 | Event MouseMove(Button As Integer , Shift As Integer , X As Single , Y As Single ) |
078 | Attribute MouseMove.VB_UserMemId = -606 |
079 | Event MouseUp(Button As Integer , Shift As Integer , X As Single , Y As Single ) |
080 | Attribute MouseUp.VB_UserMemId = -607 |
081 | Event KeyDown(KeyCode As Integer , Shift As Integer ) |
082 | Attribute KeyDown.VB_UserMemId = -602 |
083 | Event KeyPress(KeyAscii As Integer ) |
084 | Attribute KeyPress.VB_UserMemId = -603 |
085 | Event KeyUp(KeyCode As Integer , Shift As Integer ) |
086 | Attribute KeyUp.VB_UserMemId = -604 |
089 | Private Sub DrawKnob() |
090 | DrawBaseCircle '先绘制底座圆圈 |
095 | Private Sub DrawBaseCircle() |
096 | If m_Rad <= 0 Then Exit Sub |
103 | picBase.DrawWidth = 1 |
105 | For Ang = 0 To m_Steps - 1 |
106 | Dim CA As Double , CX As Double , CY As Double |
107 | CA = m_MinAng + (m_MaxAng - m_MinAng) * Ang / (m_Steps - 1) + Knob_PI * 0.5 '刻度的角度 |
110 | picBase.Line (m_Rad + CX * m_Rad * m_BaseRad, m_Rad + CY * m_Rad * m_BaseRad)-(m_Rad + CX * m_Rad, m_Rad + CY * m_Rad) '画辐射线 |
116 | DrawLightedCircle picBase, m_Rad, m_Rad, m_Rad * m_BaseRad - 1, GetSysColor(vb3DHighlight And &HFF&), GetSysColor(vb3DDKShadow And &HFF&) |
118 | DrawLightedCircle picBase, m_Rad, m_Rad, m_Rad * m_BaseRad - 3, GetSysColor(vb3DLight And &HFF&), GetSysColor(vbButtonShadow And &HFF&) |
122 | Private Sub DrawLightedCircle(Targ As PictureBox, ByVal X As Double , ByVal Y As Double , ByVal Radius As Double , ByVal Color1 As Long , ByVal Color2 As Long ) |
124 | Dim R1 As Long , G1 As Long , B1 As Long |
125 | Dim R2 As Long , G2 As Long , B2 As Long |
126 | Dim DotVal As Double , XV As Double , YV As Double , RV As Long , GV As Long , BV As Long |
129 | Targ.CurrentX = X + Radius |
134 | G1 = (Color1 And &HFF00&) \ &H100 |
135 | B1 = (Color1 And &HFF0000) \ &H10000 |
139 | G2 = (Color2 And &HFF00&) \ &H100 |
140 | B2 = (Color2 And &HFF0000) \ &H10000 |
143 | For Ang = 0 To Knob_PI * 2 Step 1 / Radius |
146 | DotVal = (XV + YV + 1) * 0.5 '与光线方向(1,1)做点乘,然后将[-1,1]变换到[0,1] |
147 | RV = R1 + (R2 - R1) * DotVal '颜色插值 |
148 | GV = G1 + (G2 - G1) * DotVal |
149 | BV = B1 + (B2 - B1) * DotVal |
150 | Targ.Line -(X + XV * Radius, Y + YV * Radius), RGB(RV, GV, BV) |
154 | Private Sub DrawLighedLine(Targ As PictureBox, ByVal X1 As Double , ByVal Y1 As Double , ByVal X2 As Double , ByVal Y2 As Double , ByVal Color1 As Long , ByVal Color2 As Long ) |
156 | Dim DirX As Double , DirY As Double , DirL As Double |
159 | DirL = Sqr(DirX * DirX + DirY * DirY) |
164 | Dim NorX As Double , NorY As Double |
168 | Dim R1 As Long , G1 As Long , B1 As Long |
169 | Dim R2 As Long , G2 As Long , B2 As Long |
170 | Dim DotVal As Double , RV As Long , GV As Long , BV As Long |
174 | G1 = (Color1 And &HFF00&) \ &H100 |
175 | B1 = (Color1 And &HFF0000) \ &H10000 |
179 | G2 = (Color2 And &HFF00&) \ &H100 |
180 | B2 = (Color2 And &HFF0000) \ &H10000 |
182 | DotVal = (NorX + NorY + 1) * 0.5 '与光线方向(1,1)做点乘,然后将[-1,1]变换到[0,1] |
183 | RV = R1 + (R2 - R1) * DotVal '颜色插值 |
184 | GV = G1 + (G2 - G1) * DotVal |
185 | BV = B1 + (B2 - B1) * DotVal |
188 | Targ.Line (X1, Y1)-(X2, Y2), RGB(RV, GV, BV) |
192 | Private Sub DrawHandle() |
193 | If m_Rad <= 0 Then Exit Sub |
196 | Ang = ValueToAngle(m_Value, m_Max) '旋钮的角度 |
199 | picKnob.PaintPicture picBase.Image, 0, 0 |
202 | If m_DrawRaisedHandle Then DrawRHandle |
206 | picKnob.DrawWidth = 1 |
207 | If m_MouseDown Then '鼠标按下的时候,填充颜色 |
208 | picKnob.FillStyle = vbSolid |
209 | picKnob.FillColor = vbHighlight |
211 | picKnob.FillStyle = 1 |
213 | picKnob.Circle (m_Rad + Cos(Ang) * m_Rad * m_BaseRad * 0.5, m_Rad + Sin(Ang) * m_Rad * m_BaseRad * 0.5), 2, vbRed |
218 | Private Sub DrawRHandle() |
222 | Ang = ValueToAngle(m_Value, m_Max) '旋钮的角度 |
225 | BaseRad = m_Rad * m_BaseRad * m_HandleRad |
228 | Dim DirX As Double , DirY As Double |
233 | Dim SideX As Double , SideY As Double |
237 | Dim RHW1 As Double , RHW2 As Double |
238 | RHW1 = m_RaisedHandleWidth1 * BaseRad |
239 | RHW2 = m_RaisedHandleWidth2 * BaseRad |
241 | Dim BackL As Double , FrontL As Double |
242 | FrontL = Sqr(BaseRad * BaseRad - RHW1 * RHW1) |
243 | BackL = Sqr(BaseRad * BaseRad - RHW2 * RHW2) |
245 | Dim Color1 As Long , Color2 As Long |
246 | Color1 = GetSysColor(vb3DHighlight And &HFF&) |
247 | Color2 = GetSysColor(vb3DDKShadow And &HFF&) |
252 | PtX(0) = m_Rad + DirX * FrontL + SideX * RHW1 |
253 | PtY(0) = m_Rad + DirY * FrontL + SideY * RHW1 |
254 | PtX(1) = m_Rad + DirX * FrontL - SideX * RHW1 |
255 | PtY(1) = m_Rad + DirY * FrontL - SideY * RHW1 |
256 | PtX(2) = m_Rad - DirX * BackL + SideX * RHW2 |
257 | PtY(2) = m_Rad - DirY * BackL + SideY * RHW2 |
258 | PtX(3) = m_Rad - DirX * BackL - SideX * RHW2 |
259 | PtY(3) = m_Rad - DirY * BackL - SideY * RHW2 |
261 | DrawLighedLine picKnob, PtX(0), PtY(0), PtX(1), PtY(1), Color1, Color2 |
262 | DrawLighedLine picKnob, PtX(1), PtY(1), PtX(3), PtY(3), Color1, Color2 |
263 | DrawLighedLine picKnob, PtX(3), PtY(3), PtX(2), PtY(2), Color1, Color2 |
264 | DrawLighedLine picKnob, PtX(2), PtY(2), PtX(0), PtY(0), Color1, Color2 |
269 | Private Function ValueToAngle( ByVal Value_ As Long , ByVal MaxValue_ As Long ) As Double |
270 | If MaxValue_ Then ValueToAngle = m_MinAng + (m_MaxAng - m_MinAng) * Value_ / MaxValue_ + Knob_PI * 0.5 |
274 | Private Function AngleToValue( ByVal Angle As Double ) As Long |
275 | If m_MaxAng = 0 Then Exit Function |
276 | Angle = Angle - Knob_PI * 0.5 |
278 | Angle = Angle + Knob_PI * 2 |
280 | While Angle > Knob_PI * 2 |
281 | Angle = Angle - Knob_PI * 2 |
283 | AngleToValue = (Angle - m_MinAng) * m_Max / (m_MaxAng - m_MinAng) |
287 | Private Sub picBase_Resize() |
292 | Private Sub picKnob_Click() |
297 | Private Sub picKnob_DblClick() |
302 | Private Sub picKnob_KeyDown(KeyCode As Integer , Shift As Integer ) |
303 | RaiseEvent KeyDown(KeyCode, Shift) |
307 | Private Sub picKnob_KeyPress(KeyAscii As Integer ) |
308 | RaiseEvent KeyPress(KeyAscii) |
312 | Private Sub picKnob_KeyUp(KeyCode As Integer , Shift As Integer ) |
313 | RaiseEvent KeyUp(KeyCode, Shift) |
317 | Private Sub picKnob_MouseDown(Button As Integer , Shift As Integer , X As Single , Y As Single ) |
319 | m_MouseAngle = GetAngle(X - m_Rad, Y - m_Rad) - ValueToAngle(m_Value, m_Max) |
321 | RaiseEvent MouseDown(Button, Shift, X, Y) |
325 | Private Sub picKnob_MouseMove(Button As Integer , Shift As Integer , X As Single , Y As Single ) |
327 | Dim NewAng As Double , OldVal As Long |
328 | NewAng = GetAngle(X - m_Rad, Y - m_Rad) - m_MouseAngle |
330 | m_Value = AngleToValue(NewAng) |
331 | If m_Value > m_Max Then m_Value = m_Max |
332 | If m_Value < 0 Then m_Value = 0 |
333 | picKnob.ToolTipText = m_Value |
335 | RaiseEvent MouseMove(Button, Shift, X, Y) |
336 | If OldVal <> m_Value Then |
337 | RaiseEvent Change(OldVal, m_Value) |
338 | m_MouseAngle = GetAngle(X - m_Rad, Y - m_Rad) - ValueToAngle(m_Value, m_Max) |
339 | ElseIf m_Value = 0 Or m_Value = m_Max Then |
340 | m_MouseAngle = GetAngle(X - m_Rad, Y - m_Rad) - ValueToAngle(m_Value, m_Max) |
346 | Private Sub picKnob_MouseUp(Button As Integer , Shift As Integer , X As Single , Y As Single ) |
349 | RaiseEvent MouseUp(Button, Shift, X, Y) |
352 | Private Sub picKnob_Resize() |
353 | picBase.Move 0, 0, picKnob.ScaleWidth, picKnob.ScaleHeight |
358 | Private Sub UserControl_Initialize() |
362 | Private Sub UserControl_InitProperties() |
368 | m_MinAng = Knob_PI / 3 |
369 | m_MaxAng = Knob_PI * 5 / 3 |
372 | m_DrawRaisedHandle = True |
373 | m_RaisedHandleWidth1 = 0.3 |
374 | m_RaisedHandleWidth2 = 0.3 |
377 | Private Sub UserControl_ReadProperties(PropBag As PropertyBag) |
378 | m_Max = PropBag.ReadProperty( "Max" , m_Max) |
379 | m_Value = PropBag.ReadProperty( "Value" , m_Value) |
380 | m_Steps = PropBag.ReadProperty( "Steps" , m_Steps) |
381 | m_BaseRad = PropBag.ReadProperty( "BaseRadius" , m_BaseRad) |
382 | m_HandleRad = PropBag.ReadProperty( "HandleRadius" , m_HandleRad) |
383 | m_MinAng = PropBag.ReadProperty( "MinAngle" , m_MinAng) |
384 | m_MaxAng = PropBag.ReadProperty( "MaxAngle" , m_MaxAng) |
385 | m_DrawGrad = PropBag.ReadProperty( "DrawGraduation" , m_DrawGrad) |
386 | m_DrawPoint = PropBag.ReadProperty( "DrawPoint" , m_DrawPoint) |
387 | m_DrawRaisedHandle = PropBag.ReadProperty( "DrawRaisedHandle" , m_DrawRaisedHandle) |
388 | m_RaisedHandleWidth1 = PropBag.ReadProperty( "RaisedHandleWidth1" , m_RaisedHandleWidth1) |
389 | m_RaisedHandleWidth2 = PropBag.ReadProperty( "RaisedHandleWidth2" , m_RaisedHandleWidth2) |
390 | picKnob.BorderStyle = PropBag.ReadProperty( "BorderStyle" , picKnob.BorderStyle) |
391 | m_Rad = picKnob.ScaleHeight \ 2 |
395 | Private Sub UserControl_WriteProperties(PropBag As PropertyBag) |
396 | PropBag.WriteProperty "Max" , m_Max |
397 | PropBag.WriteProperty "Value" , m_Value |
398 | PropBag.WriteProperty "Steps" , m_Steps |
399 | PropBag.WriteProperty "BaseRadius" , m_BaseRad |
400 | PropBag.WriteProperty "HandleRadius" , m_HandleRad |
401 | PropBag.WriteProperty "MinAngle" , m_MinAng |
402 | PropBag.WriteProperty "MaxAngle" , m_MaxAng |
403 | PropBag.WriteProperty "DrawGraduation" , m_DrawGrad |
404 | PropBag.WriteProperty "DrawPoint" , m_DrawPoint |
405 | PropBag.WriteProperty "DrawRaisedHandle" , m_DrawRaisedHandle |
406 | PropBag.WriteProperty "RaisedHandleWidth1" , m_RaisedHandleWidth1 |
407 | PropBag.WriteProperty "RaisedHandleWidth2" , m_RaisedHandleWidth2 |
408 | PropBag.WriteProperty "BorderStyle" , picKnob.BorderStyle |
412 | Private Sub UserControl_Resize() |
413 | If Width > Height Then |
416 | ElseIf Width < Height Then |
420 | picKnob.Height = ScaleHeight |
421 | m_Rad = picKnob.ScaleHeight \ 2 |
426 | Private Function GetAngle( ByVal X As Double , ByVal Y As Double ) As Double |
427 | 'X为Cos计算出来的,Y为Sin计算出来的 |
429 | GetAngle = Atn(Y / X) |
431 | GetAngle = Atn(Y / X) + Knob_PI |
433 | GetAngle = Knob_PI / 2 |
435 | GetAngle = Knob_PI * 3 / 2 |
439 | '边框属性,继承的PictureBox的边框属性 |
440 | Property Get BorderStyle() As Long |
441 | Attribute BorderStyle.VB_Description = "The style of the border. Same as PictureBox." |
442 | Attribute BorderStyle.VB_ProcData.VB_Invoke_Property = ";外观" |
443 | Attribute BorderStyle.VB_UserMemId = -504 |
444 | BorderStyle = picKnob.BorderStyle |
447 | Property Let BorderStyle( ByVal NewBorderStyle As Long ) |
448 | picKnob.BorderStyle = NewBorderStyle |
449 | m_Rad = picKnob.ScaleHeight \ 2 |
451 | PropertyChanged "BorderStyle" |
455 | Property Get Value() As Long |
456 | Attribute Value.VB_Description = "The value of the knob." |
457 | Attribute Value.VB_ProcData.VB_Invoke_Property = ";行为" |
458 | Attribute Value.VB_UserMemId = 0 |
462 | Property Let Value( ByVal NewValue As Long ) |
465 | ElseIf NewValue > m_Max Then |
471 | PropertyChanged "Value" |
475 | Property Get Max() As Long |
476 | Attribute Max.VB_Description = "The maximum value" |
477 | Attribute Max.VB_ProcData.VB_Invoke_Property = ";行为" |
481 | Property Let Max( ByVal NewMaxValue As Long ) |
482 | If NewMaxValue < 0 Then |
487 | If m_Value > m_Max Then m_Value = m_Max |
493 | Property Get MinAngle() As Double |
494 | Attribute MinAngle.VB_Description = "The minimum angle the knob can turn." |
495 | Attribute MinAngle.VB_ProcData.VB_Invoke_Property = ";外观" |
496 | MinAngle = m_MinAng * 180 / Knob_PI |
499 | Property Let MinAngle( ByVal NewMinAngle As Double ) |
500 | m_MinAng = NewMinAngle * Knob_PI / 180 |
501 | While m_MinAng > Knob_PI * 2 |
502 | m_MinAng = m_MinAng - Knob_PI * 2 |
505 | m_MinAng = m_MinAng + Knob_PI * 2 |
507 | If m_MaxAng < m_MinAng Then |
514 | PropertyChanged "MinAngle" |
518 | Property Get MaxAngle() As Double |
519 | Attribute MaxAngle.VB_Description = "The maximum angle the knob can turn." |
520 | Attribute MaxAngle.VB_ProcData.VB_Invoke_Property = ";外观" |
521 | MaxAngle = m_MaxAng * 180 / Knob_PI |
524 | Property Let MaxAngle( ByVal NewMaxAngle As Double ) |
525 | m_MaxAng = NewMaxAngle * Knob_PI / 180 |
526 | While m_MaxAng > Knob_PI * 2 |
527 | m_MaxAng = m_MaxAng - Knob_PI * 2 |
530 | m_MaxAng = m_MaxAng + Knob_PI * 2 |
532 | If m_MinAng > m_MaxAng Then |
539 | PropertyChanged "MaxAngle" |
543 | Property Get Steps() As Long |
544 | Attribute Steps.VB_Description = "The steps of the graduation." |
545 | Attribute Steps.VB_ProcData.VB_Invoke_Property = ";外观" |
549 | Property Let Steps( ByVal NewSteps As Long ) |
550 | If NewSteps > m_Max Then |
552 | ElseIf NewSteps < 0 Then |
558 | PropertyChanged "Steps" |
562 | Property Get BaseRadius() As Double |
563 | Attribute BaseRadius.VB_Description = "The radius of the base circle." |
564 | Attribute BaseRadius.VB_ProcData.VB_Invoke_Property = ";外观" |
565 | BaseRadius = m_BaseRad |
568 | Property Let BaseRadius( ByVal NewBaseRadius As Double ) |
569 | If NewBaseRadius < 0 Then |
572 | m_BaseRad = NewBaseRadius |
575 | PropertyChanged "BaseRadius" |
579 | Property Get HandleRadius() As Double |
580 | Attribute HandleRadius.VB_Description = "The radius(or length) of the raised handle." |
581 | Attribute HandleRadius.VB_ProcData.VB_Invoke_Property = ";外观" |
582 | HandleRadius = m_HandleRad |
585 | Property Let HandleRadius( ByVal NewHandleRadius As Double ) |
586 | If NewHandleRadius < 0 Then |
589 | m_HandleRad = NewHandleRadius |
592 | PropertyChanged "HandleRadius" |
596 | Property Get DrawGraduation() As Boolean |
597 | Attribute DrawGraduation.VB_Description = "Draw the graduation if it was true." |
598 | Attribute DrawGraduation.VB_ProcData.VB_Invoke_Property = ";外观" |
599 | DrawGraduation = m_DrawGrad |
602 | Property Let DrawGraduation( ByVal NewVal As Boolean ) |
605 | PropertyChanged "DrawGraduation" |
609 | Property Get DrawPoint() As Boolean |
610 | Attribute DrawPoint.VB_Description = "Draw the red point if it was true." |
611 | Attribute DrawPoint.VB_ProcData.VB_Invoke_Property = ";外观" |
612 | DrawPoint = m_DrawPoint |
615 | Property Let DrawPoint( ByVal NewVal As Boolean ) |
618 | PropertyChanged "DrawPoint" |
622 | Property Get DrawRaisedHandle() As Boolean |
623 | Attribute DrawRaisedHandle.VB_Description = "Draw the raised handle if it was true." |
624 | Attribute DrawRaisedHandle.VB_ProcData.VB_Invoke_Property = ";外观" |
625 | DrawRaisedHandle = m_DrawRaisedHandle |
628 | Property Let DrawRaisedHandle( ByVal NewVal As Boolean ) |
629 | m_DrawRaisedHandle = NewVal |
631 | PropertyChanged "DrawRaisedHandle" |
635 | Property Get RaisedHandleWidth1() As Double |
636 | Attribute RaisedHandleWidth1.VB_Description = "The width of the raised handle." |
637 | Attribute RaisedHandleWidth1.VB_ProcData.VB_Invoke_Property = ";外观" |
638 | RaisedHandleWidth1 = m_RaisedHandleWidth1 |
641 | Property Let RaisedHandleWidth1( ByVal NewVal As Double ) |
642 | m_RaisedHandleWidth1 = NewVal |
644 | PropertyChanged "RaisedHandleWidth1" |
648 | Property Get RaisedHandleWidth2() As Double |
649 | Attribute RaisedHandleWidth2.VB_Description = "The width of the raised handle." |
650 | Attribute RaisedHandleWidth2.VB_ProcData.VB_Invoke_Property = ";外观" |
651 | RaisedHandleWidth2 = m_RaisedHandleWidth2 |
654 | Property Let RaisedHandleWidth2( ByVal NewVal As Double ) |
655 | m_RaisedHandleWidth2 = NewVal |
657 | PropertyChanged "RaisedHandleWidth2" |
|