返回首页

{S0}简介
我必须强迫症(强迫性控制障碍)。标准的TrackBar我讨厌很长一段时间,但我只是把它到现在为止。我终于厌倦了枯燥的外观,代码TextBox或与它的标签显示的价值,它是什么标签。所以,这里是我需要的TrackBar的,希望它可以帮助你太多。有太多的属性,只是像我通常会列出他们,所以我决定列出的属性组的功能和整个列表截图。对照组包含控制的边界,价值和定位属性。的floatValue的价值是用鼠标移动滑块。标签是以上的TrackBar出现的文本。滑块线,刻度,滑块按钮本身。UpDownButtons的TrackBar的每个按钮增加一值。ValueBox框显示值。 属性大厦
建筑区域包含例程的设置布局,规模,岗位和控制所有的属性设置为基础的部分。
重载paint事件自定义绘制每一块控制在合适的地点以正确的方向。

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

        MyBase.OnPaint(e)



        'Setup the Graphics

        Dim g As Graphics = e.Graphics

        g.SmoothingMode = SmoothingMode.AntiAlias

        g.TextRenderingHint = Drawing.Text.TextRenderingHint.AntiAlias



        'Draw a Border around the control if requested

        If _BorderShow Then

            g.DrawRectangle(New Pen(_BorderColor), _

                0, 0, Me.Width - 1, Me.Height - 1)

        End If



        'Add the value increment buttons if requested

        If _UpDownShow Then DrawUpDnButtons(g)



        'Add the Line and Tick Marks

        DrawSliderLine(g)



        'Draw the Label Text if requested

        If _LabelShow Then

            DrawLabel(g)

            'g.DrawRectangle(Pens.Gray, rectLabel)

        End If



        'Add the Slider button

        DrawSlider(g)



        'Draw the Value above the Slider if requested

        If _FloatValue AndAlso IsOverSlider AndAlso _

          MouseState = eMouseState.Down Then

            DrawFloatValue(g)

        End If



        'Draw the Box displaying the value if requested

        If Not _ValueBox = eValueBox.None Then

            DrawValueBox(g)

        End If



        'Draw Focus Rectangle around control if requested 

        If _ShowFocus AndAlso Me.Focused Then

            ControlPaint.DrawFocusRectangle(g, New Rectangle( _

            2 + CInt(Not _BorderShow), 2 + CInt(Not _BorderShow), _

            Me.Width - ((2 + CInt(Not _BorderShow)) * 2), _

            Me.Height - ((2 + CInt(Not _BorderShow)) * 2)), _

            Color.Black, Me.BackColor)

        End If



    End Sub

我用基本的GDI函数绘制每一块的控制。我将重点介绍一些更好的部件。
在DrawUpDnButtons,我基本上有一个按钮,需要绘制的四个方向和哪一方是控制的方法之一。按钮本身就是一个渐变颜色填充的矩形。诀窍是箭头。我可以计算出每个箭头的位置和点创建为每一个单独的GraphicsPath,但我用一个矩阵来旋转和/或翻译一个简单的GraphicsPath的正确位置。
首先设置三个点,并添加行创建它们之间的三角箭头^形状:{C}
左手按钮,GraphicsPath的是方向正确,所以只需要进行翻译(移动)按钮的矩形内合适的位置。
With rectDownButton

    mx.Translate(5, CSng((rectDownButton.Y _

      + (rectDownButton.Height / 2)) - 6))

    gp.Transform(mx)

    g.DrawPath(pn, gp)

End With

为右手按钮,GraphicsPath的需要翻转,但没有一个翻转的内置函数。使用此GraphicsPath的水平,而不是翻转:新矩阵(-1,0,0,1,图像的宽度,0​​)。
With rectUpButton

     mx = New Matrix(-1, 0, 0, 1, 5, 0)

     mx.Translate(.X + 9, 0, MatrixOrder.Append)

     gp.Transform(mx)

     g.DrawPath(pn, gp)

End With

上部按钮,GraphicsPath的需要旋转90度。寻找中心点和RotateAt这一点。
With rectDownButton

     mx.RotateAt(90, New PointF(gp.GetBounds.Width / 2, _

         gp.GetBounds.Height / 2))

     mx.Translate(CSng((rectDownButton.X + _

        (rectDownButton.Width / 2)) - 3), 4, MatrixOrder.Append)

     gp.Transform(mx)

     g.DrawPath(pn, gp)

End With

对于较低的按钮,GraphicsPath的需求再次被翻转。使用此垂直翻转图像:新矩阵(1,0,0,-1,0,这里图像的高度)。
With rectUpButton

     mx = New Matrix(1, 0, 0, -1, 0, 10)

     mx.Translate(0, .Y + 6, MatrixOrder.Append)

     gp.Transform(mx)

     g.DrawPath(pn, gp)

End With

的中心点,并在滑块刷FocusScales类型的PointF。当您创建一个新类型的PointF属性,你会发现这是在PropertyGrid中显示为灰色,但如果一个属性是Point类型,它会在PropertyGrid编辑正确。问题是,没有内置的PointF的TypeConverter。这其实是很容易解决的。
一个没有一个自定义TypeConverter的PointF类型的属性:工程代码,但你不能在PropertyGrid编辑。{S2}
随着PointFConverter,就像点属性在PropertyGrid执行。
创建一个属性,并添加引用我们要添加PointFConverter类的TypeConverter属性。
Private _SliderHighlightPt As PointF = New PointF(-5.0F, -2.5F)

<Category("Appearance Slider")> _

<Description("Point on the Slider for the Highlight Color")> _

<TypeConverter(GetType(PointFConverter))> _

Public Property SliderHighlightPt() As PointF

    Get

        Return _SliderHighlightPt

    End Get

    Set(ByVal value As PointF)

        _SliderHighlightPt = value

        Me.Invalidate()

    End Set

End Property

PointFConverter类继承ExpandableObjectConverter,覆盖的CanConvertFrom的ConvertFrom的ConvertTo功能。
Friend Class PointFConverter : Inherits ExpandableObjectConverter



    Public Overloads Overrides Function CanConvertFrom( _

        ByVal context As System.ComponentModel.ITypeDescriptorContext, _

        ByVal sourceType As System.Type) As Boolean



        If (sourceType Is GetType(String)) Then

            Return True

        End If

        Return MyBase.CanConvertFrom(context, sourceType)



    End Function



    Public Overloads Overrides Function ConvertFrom( _

        ByVal context As System.ComponentModel.ITypeDescriptorContext, _

        ByVal culture As System.Globalization.CultureInfo, _

        ByVal value As Object) As Object



        If TypeOf value Is String Then

            Try

                Dim s As String = CType(value, String)

                Dim ConverterParts(2) As String

                ConverterParts = Split(s, ",")

                If Not IsNothing(ConverterParts) Then

                    If IsNothing(ConverterParts(0)) Then ConverterParts(0) = "-5"

                    If IsNothing(ConverterParts(1)) Then ConverterParts(1) = "-2.5"

                    Return New PointF(CSng(ConverterParts(0).Trim), _

                                      CSng(ConverterParts(1).Trim))

                End If

            Catch ex As Exception

                Throw New ArgumentException("Can not convert '" & _

                    CStr(value) & "' to type Corners")

            End Try

        Else

            Return New PointF(-5.0F, -2.5F)

        End If



        Return MyBase.ConvertFrom(context, culture, value)





    End Function



    Public Overloads Overrides Function ConvertTo( _

        ByVal context As System.ComponentModel.ITypeDescriptorContext, _

        ByVal culture As System.Globalization.CultureInfo, _

        ByVal value As Object, ByVal destinationType As System.Type) As Object



        If (destinationType Is GetType(System.String) _

            AndAlso TypeOf value Is PointF) Then



            Dim ConverterProperty As PointF = CType(value, PointF)

            ' build the string representation 

            Return String.Format("{0}, {1}", _

                    ConverterProperty.X, _

                    ConverterProperty.Y)

        End If

        Return MyBase.ConvertTo(context, culture, value, destinationType)



    End Function



End Class 'PointFConverter Class
鼠标事件
这里就是我们检查一下光标,如果按下鼠标按钮控制的一部分。根据这一信息,该值相应的调整。
因为在MouseDown,点击等一次性处理,需要一个计时器看到如果鼠标仍然下降,若然再次改变值。我不希望它尽快跑掉,因为它被点击的,所以有一个内置延迟权后点击鼠标,然后延迟后,将开始递增的价值。另一个问题是,如果最小/最大跨度大,它会抓取超慢和小跨度将压缩太快,所以定时器的时间间隔是调整的基础上跨度大。
Private Sub MouseTimer_Tick(ByVal sender As Object, _

    ByVal e As System.EventArgs) Handles MouseTimer.Tick

    'Check if mouse was just clicked

    If MouseHoldDownTicker < 5 Then

        MouseHoldDownTicker += 1

        'Interval was set to 100 on MouseDown

        'Tick off 5 times and then reset the Timer Interval

        '  based on the Min/Max span

        If MouseHoldDownTicker = 5 Then

            MouseTimer.Interval = CInt(Math.Max _

                (10, 100 - ((_MaxValue - _MinValue) / 10)))

        End If

    Else

        'Change the value until the mouse is released

        Me.Value += MouseHoldDownChange

    End If

End Sub
关键事件
我想可以按箭头键调整值。这听起来简单。我想,我只想检查e.KeyValue KeyUp事件,并相应地调整值。好了,没有那么简单。问题是,在UserControl继承按钮,它会自动以不同的方式处理箭头键。 KeyUp事件后,重点跳转到下一个控件在Tab键顺序,即使您使用e.Handled和e.SuppressKeyPress。我无法阻止的重点有所改变。然后,我想我会用KeyDown事件,但猜测的箭头是什么,有自动忽略。要解决这种行为,我重写IsInputKey功能,让箭头键。在此之后,焦点不会跳走了。
Protected Overrides Function IsInputKey( _

          ByVal keyData As System.Windows.Forms.Keys) As Boolean

    'Because a Usercontrol ignores the arrows in the KeyDown Event

    'and changes focus no matter what in the KeyUp Event

    'This is needed to fix the KeyDown problem

    Select Case keyData And Keys.KeyCode

        Case Keys.Up, Keys.Down, Keys.Right, Keys.Left

            Return True

        Case Else

            Return MyBase.IsInputKey(keyData)

    End Select

End Function



Private Sub gTrackBar_KeyUp(ByVal sender As Object, _

            ByVal e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyUp

    

    Dim adjust As Integer = _ChangeSmall

    If e.Shift Then

        adjust = _ChangeLarge

    End If



    Select Case e.KeyValue

        Case Keys.Up, Keys.Right

            Me.Value += adjust



        Case Keys.Down, Keys.Left

            Me.Value -= adjust

    End Select

End Sub
历史版本1.0 - 2009年3月版本1.2 - 2009年4月新增焦点矩形分为自身的矩形区域的标签为更好地布局和浆纱总体布局修复版本1.3 - 2009年4月处理负范围版本1.4 - 2010年7月新增图像滑块新增UpDownShow隐藏和关闭向上/向下按钮新增计时器,直到释放鼠标改变其值(在短暂延迟之后)| SSDiver2112

回答

评论会员:游客 时间:2012/01/24
非常好的控制,感谢分享。是否有可能改变滑块按钮的位置,沿滑块在这样一个滑块的值是不会改变的方式
?SSDiver2112
评论会员:游客 时间:2012/01/24
我不理解你问的雌马。你想移动滑块,但不能改变的价值?为了更好地理解:如果是这样的目的是什么的
?swehunter2000
评论会员:游客 时间:2012/01/24
嗨,我想用它作为一个滚动的胸罩,我有它towork,但我得到一些死亡空间,因为我的ListBox包含21个项目,我设置股指更多的解释:{A}
swehunter2000
评论会员:游客 时间:2012/01/24
我在属性选择的形象,但什么也没有发生...什么时候,我做拧?(我试图改变滑块"按钮")|SSDiver2112
您已设置Br​​ushStyle的属性图片过
评论会员:会员7017154 时间:2012/01/24
!伟大的工作确实

我想用一时滑块的滑块值的含义后得到改变,我想
设置滑块中间。

如果我设置gTrackBar1.Value =最大/ 2处理ValueChanged事件后,滑块并不总是返回到中间。
这又如何确定?


阿哈
评论会员:SSDiver2112 时间:2012/01/24
如果使用的是垂直方向,我发现了一个错误在计算时是minvalue大于零。进行这些更改来解决:
请改变这种SetSliderRect私人小组()


UpdateSlider(CInt(rectSlider.Y + (rectSlider.Height * _

     (((_MaxValue + adj) - _Value - adj) _

     / ((_MaxValue + adj) - (_MinValue + adj))))))

 


,并让私人小组SetSliderValue else部分(#点PT)
改变

Value = ((_MaxValue + adj) - CInt(((sngSliderPos - rectSlider.Y) _

     / (rectSlider.Height / ((_MaxValue + adj) - (_MinValue + adj)))))) - adj

 


如果我正确理解你的问题... ...如果范围是100到50,你把它设置为50,这将是最终没有中间。
将它设置为75至100和50之间的中间点。
MaxValue的 - ((MaxValue的MINVALUE)/ 2)给你的中间值

SSDiver2112
评论会员:会员7017154 时间:2012/01/24
伟大的工作!

我在设计最高100最低50

但是,当我设置上ChangeValue事件gTrackBar1.Value = 50,滑块不回去
到中间。

能否请您帮助?


阿哈
评论会员:Johnnybj 时间:2012/01/24
!非常可观
滑块可以垂直或水平位置...
难道可以在任何角度位置的滑块控制(即其旋转360度)
评论会员:?SSDiver2112 时间:2012/01/24
是,它绝对可以用一个矩阵和一个对角线的运动转换到垂直之一方式。这将是一个有点棘手,但我理解的基本原则,因为我上一个项目是现在使用一些轮换工作。唯一的其他困难,我可以预见的是对每一方的背景空间。获得真正的透明度是艰难和裁剪反锯齿边缘的任何一个地区的餐厅
评论会员:。Johnnybj 时间:2012/01/24
感谢您的答复。你见过你当前的项目,此其一; http://www.codeproject.com/KB/WPF/WPFRoateControl.aspx

我明白,把一个旋转控制滑块,将采取不同的级别的复杂性。有关WPF至今我已阅读,你可以用现有的常规用户控件自定义WPF控件。对此您的想法
评论会员:?SSDiver2112 时间:2012/01/24
我很好奇有关WPF,但还没有时间尚未挖掘到它。所以现在我并不真正了解不够说。

我刚刚张贴的文章,我在前面提到:

有可能在它的东西,你可以用它来帮助你。
SSDiver2112
评论会员:videoed 时间:2012/01/24
!首先:感谢您的控制

我想使用一个播放列表编辑,并显示为"MM:SS"的floatValue。
我已经成功地分配一个液晶字体的FloatValueFont,也改变了您的DrawFloatValue分:
DIM dmillTime的String = Milli2MMSS(_value)"dmillTime =>类似"00:00"
昏暗的SZ的SizeF = g.MeasureString(dmillTime,_FloatValueFont,新的PointF(0,0),StringFormat.GenericDefault)
...
g.DrawString(dmillTime,_FloatValueFont,新SolidBrush(_FloatValueFontColor),矩形,SF)Unfortunaly的​​floatValue cutted,在这张照片中所示的TrackBar尺寸:


我怎样才能防止这种情况呢?在此先感谢,
videoed 修改,6月23日(星期四)上午01:56,2011
评论会员:SSDiver2112 时间:2012/01/24
RECT构造函数是不是在您的文章,所以我不能肯定地告诉。但是,基于图像,它看起来像RECT是不够大,所以它是切断文本不适合。
SSDiver2112
评论会员:videoed 时间:2012/01/24
矩形的构造,我已经改变只有一点点减少浮点值滑块之间的距离(rect.Y = 5,而不是:rect.Y = 2)
我添加了一个属性FloatValueAsTime,能够显示毫米:ss或数字

完成DrawFloatValue子:私人小组DrawFloatValue(为ByRef为图形G)
& #160;DIM SZ的SizeF
DIM dmillTime为String ="00:00"
如果_FloatValueAsTime然后
dmillTime = Milli2HMS(_value)"dmillTime =>类似"00:00"
SZ = g.MeasureString(dmillTime,_FloatValueFont,新的PointF(0,0),_,
  ; StringFormat.GenericDefault)
ELSE
SZ = g.MeasureString(_Value.ToString,_FloatValueFont,新的PointF(0,0),
StringFormat.GenericDefault)
最终如果

昏暗的矩形,矩形
昏暗的PBR作为PathGradientBrush
昏暗的GP作为新的GraphicsPath
如果_Orientation = Windows.Forms.Orientation.Horizo​​ntal然后
& #160; RECT =新的矩形(CINT(sngSliderPos - (sz.Width / 2)),
CINT((rectSlider.Height / 2)rectSlider.Y - _
  ; (_SliderSize.Height / 2) - 1 - sz.Height),_
CINT(sz.Width)1,CINT(sz.Height))
ELSE
 60; RECT =新的矩形(CINT((rectSlider.Width / 2) - (sz.Width / 2)),_
CINT(sngSliderPos - sz.Height - (_SliderSize.Height / 2) - 3),_
CINT(sz.Width 1),CINT(sz.Height 2))
最终如果

 0; gp.AddRectangle(RECT)
PBR =新PathGradientBrush(GP)
pbr.SurroundColors =新色(){Color.Transparent}
如果Me.BackColor = Color.Transparent然后
 0; Me.Parent.BackColor pbr.CenterColor =
&# 160; ELSE
Me.BackColor pbr.CenterColor =
最终如果
g.FillRectangle(PBR,RECT)

rect.Y = 5",以减少浮点值之间的距离滑块
"rect.Y = 2"原始

&# 160;如果_FloatValueAsTime然后
g.DrawString(dmillTime,_FloatValueFont,新SolidBrush(_FloatValueFontColor),矩形,SF)
ELSE
g.DrawString(_Value.ToString,_FloatValueFont,新SolidBrush(_FloatValueFontColor),
RECT,SF)
最终如果

pbr.Dispose()
& #160; gp.Dispose()
END SUB
评论会员:wbp47 时间:2012/01/24
这是一个非常方便的控制。我发现当我使用它,有一些问题是minvalue时不为零时,方向设置为纵向。我已经为这些修正 - 做我送他们到他们列入

威廉
评论会员:SSDiver2112 时间:2012/01/24
wbp47,
通常人们只张贴在这里,让大家都可以看到他们,我会添加他们如果有必要时允许。

ssdiver2112
评论会员:会员3574825 时间:2012/01/24
您好,

首先感谢所有提供这样一个美丽的和可定制的TrackBar的。
我与它的滚动事件的小问题。我有所谓的"滚动"的TrackBar的事件,但它似乎控制不是提高事件。我已经检查在调试模式下,是不是到滚动事件。
能否请你告诉我,我做错了什么?任何帮助将得到高度赞赏

关于
评论会员:SSDiver2112 时间:2012/01/24
作为一个自定义控件,您会看到列出通用的滚动事件,但它不是编码。 ValueChanged事件做同样的事情,所以我没有多余的滚动事件。如果你必须有文字滚动事件,然后重复ValueChanged事件控制代码。否则只使用ValueChanged事件捕捉gTrackBar改变。

SSDiver2112
评论会员:t_nedelchev 时间:2012/01/24
喜SSDiver2112
这是一个伟大的TrackBar.When我propertie MINVALUE异于零(TickType是两者),例如30蜱是不slider.Why开始是
评论会员:?SSDiver2112 时间:2012/01/24
好赶上,我hadn "T注意到之前,因为这种行为并不总是显示。没有工作和其他一些数字组合。

要修复的Tick问题小组DrawSliderLine
与此更正的代码替换:


If _TickType <> eTickType.None Then

    For i As Integer = 0 To _MaxValue - _MinValue Step _TickInterval

        Tickpos = CInt(rectSlider.X + (rectSlider.Width * _

            (i / (_MaxValue - _MinValue))))

        g.DrawLine(tpn, Tickpos, CSng(rectSlider.Height / 2) + t1 + lAdj, _

            Tickpos, CSng(rectSlider.Height / 2) + t2 + lAdj)

        If _TickType = eTickType.Both Then

            g.DrawLine(tpn, Tickpos, CSng(rectSlider.Height / 2) - t1 + lAdj, _

                Tickpos, CSng(rectSlider.Height / 2) - t2 + lAdj)

        End If

    Next

End If


我注意到的另一件事是在MaxValue的属性

涨跌:

If value <= _MinValue Then value = _MinValue - 10
到:


If value <= _MinValue Then value = _MinValue + 10


SSDiver2112
评论会员:t_nedelchev 时间:2012/01/24
。SSDiver2112
现在一切都OK
评论会员:。Sousuke_ 时间:2012/01/24
如何改变子TBSlider_MouseDown喜欢在媒体播放器上设置点值我点击,
评论会员:?SSDiver2112 时间:2012/01/24
Sousuke_,

我首先添加一个布尔JumpToMouse属性,然后下面的变化MouseDown事件。 如果您只希望特定的行为,忘记了财产,并且只使用下面的真实部分的JumpToMouse代码。
如果你想它跳转到鼠标,然后停止,删除IsOverSlider = TRUE线,否则将继续遵循鼠标,直到按钮被释放。只要决定你喜欢的行为。

这是从MouseMove事件相同的代码,这样他们就可以合并成一个子例程,如果你想减少redundency。


        If IsOverSlider Then

            CurrSliderColor = _ColorDown

            CurrSliderBorderColor = _ColorDownBorder

            CurrSliderHiLtColor = _ColorDownHiLt

        ElseIf rectSlider.Contains(e.Location) Then

            If _JumpToMouse Then

                sngSliderPos = pos

                IsOverSlider = True

                If _Orientation = Windows.Forms.Orientation.Horizontal Then

                    Me.Value = CInt(((sngSliderPos - rectSlider.X) _

                        / (rectSlider.Width / (_MaxValue - _MinValue))) + _MinValue)

                    UpdateSlider(e.X)

                Else

                    Dim adj As Integer = 0

                    If _MinValue < 0 Then adj = Math.Abs(_MinValue)

                    Me.Value = ((_MaxValue + adj) - CInt(((sngSliderPos - rectSlider.Y) _

                        / (rectSlider.Height / ((_MaxValue + adj) - (_MinValue + adj)))) _

                        + (_MinValue + adj))) - adj

                    UpdateSlider(e.Y)

                End If

            Else

                If pos < sngSliderPos Then

                    MouseHoldDownChange = _ChangeLarge * Orient

                    Me.Value += MouseHoldDownChange

                Else

                    MouseHoldDownChange = -(_ChangeLarge * Orient)

                    Me.Value += MouseHoldDownChange

                End If

                MouseTimer.Start()

            End If

        End If

 

希望这有助于,
SSDiver2112
评论会员:de_mts 时间:2012/01/24
HI我真的很喜欢你的代码。但是,当我改变滑块,我得到一个滑块周围灰色的虚线边框。是否有可能禁用此?
BorderShow是虚假的。
感谢