zoukankan      html  css  js  c++  java
  • DragListControl:一种新类型的控件,用于从列表中选择项

    介绍 我想创建一个控件来为从列表中选择项提供不同于通常的用户体验。 背景 通过直接继承控件类,并在其中插入位图(用于显示当前项)和弹出框(用于显示可滚动的元素列表),我创建了一个新控件。 所选项目的上面和下面是一个区域,可以直接选择上一个或下一个项目。项目选择由两个区域完成,执行动画显示变化执行: 选择项的第二种方法是从控件上的任何点开始向上或向下拖动鼠标。元素将是可转换为字符串的任何类型的对象的列表: 代码描述 我将代码分为三个部分:第一部分用于定义自定义属性和事件,第二部分用于用户交互,第三部分用于数据的表示。代码被完全注释并且(希望)容易理解。 一些笔记 隐藏,收缩,复制Code

    ''' <summary>Permits Private Components (Picture)</summary>
    Private components As System.ComponentModel.IContainer
    
    ''' <summary>PictureBox Showing the current item</summary>
    Private WithEvents PctCurrentItem As System.Windows.Forms.PictureBox
    ''' <summary>PictureBox Showing the List during the drag</summary>
    Private WithEvents PctItemList As System.Windows.Forms.PictureBox
    ''' <summary>Popup Window showing the list</summary>
    Private WithEvents PopUpD As ToolStripDropDown
    ''' <summary>ControlHost of PopUp Containing the PctItemList</summary>
    Private PopUpHost As ToolStripControlHost
    ''' <summary>Timer: If the DragDrop is open: Permit the list refresh checking
    ''' for the mouse position. If the DragDrop is closed,
    ''' it performs the Current shifting</summary>
    Private WithEvents Tmr As New Timer With {.Interval = 10}
    
    ''' <summary>Initializing</summary>
    Public Sub New()
        PopUpD = New ToolStripDropDown
        PctCurrentItem = New PictureBox
        PctItemList = New PictureBox
        PopUpHost = New ToolStripControlHost(PctItemList)
        Me.Controls.Add(PctCurrentItem)
        PopUpD.Items.Add(PopUpHost)
        Me_FontChanged(Nothing, Nothing)
    End Sub
    
    ''' <summary>Change of the font: resize the picture of current item,
    ''' Constraint the minimum size</summary>
    Private Sub Me_FontChanged(sender As Object, e As EventArgs) Handles Me.FontChanged
        Dim TextSize As SizeF = PctCurrentItem.CreateGraphics().MeasureString_
                                ("0", PctCurrentItem.Font)
        PctCurrentItem.Height = CInt(TextSize.Height + 2)
        Me.MinimumSize = New System.Drawing.Size(CInt(TextSize.Width * 1.5), _
                         PctCurrentItem.Height + 10)
        Me_Resize(Nothing, Nothing)
    End Sub
    
    ''' <summary>Permits the focus repainting</summary>
    Private Sub Me_GotFocus(sender As Object, e As EventArgs) _
                            Handles Me.GotFocus, Me.LostFocus
        Me.Invalidate()
    End Sub
    

    我使控件的高度比渲染元素的字体高度至少高出50%,以便为上一个/下一个选择区域留出空间。我不知道这是不是一个错误的或有问题的模式,但它似乎是最简单的方式,迫使用户保留空间,但仍然允许创造一个伟大的喜爱。 更改控件的字体将执行内部元素的缩放和最小大小的设置,还将执行内部控件的重新定位和下一次刷新(通过Me_Resize)。 GotFocus和LostFocus事件将使该区域无效,因为焦点正在显示。 关于属性和事件 隐藏,收缩,复制Code

    ''' <summary>CurrentIndexChanged</summary>
    Public Event CurrentIndexChanged(sender As Object, e As EventArgs)
    
    ''' <summary>Width of arrows</summary>
    Private _ArrowWidth As Single = 1
    ''' <summary>Width of arrows</summary>
    <System.ComponentModel.Browsable(True)>
    <System.ComponentModel.DefaultValue(1.0!)>
    Public Property ArrowWidth As Single
        Get
            Return _ArrowWidth
        End Get
        Set(value As Single)
            If _ArrowWidth <> value Then
                _ArrowWidth = value
                Me.Invalidate()
            End If
        End Set
    End Property
    
    ''' <summary>Color of arrows</summary>
    Private _ArrowColor As Color = Color.DarkGray
    ''' <summary>Color of arrows</summary>
    <System.ComponentModel.Browsable(True)>
    <System.ComponentModel.DefaultValue(GetType(Color), "DarkGray")>
    Public Property ArrowColor As Color
        Get
            Return _ArrowColor
        End Get
        Set(value As Color)
            If _ArrowColor <> value Then
                _ArrowColor = value
                Me.Invalidate()
            End If
        End Set
    End Property
    
    ''' <summary>Item List</summary>
    Private Property _Items As Array = New Object() {}
    ''' <summary>Item List</summary>
    ''' <remarks>DefaultValueAttribute is not settable
    ''' (An empty Array is always different from another empty array)</remarks>
    <System.ComponentModel.Browsable(True)>
    Public Property Items As Array
        Get
            Return _Items
        End Get
        Set(value As Array)
            If value.GetUpperBound(0) <> _Items.GetUpperBound(0) _
            OrElse (value.GetUpperBound(0) >= 0 AndAlso Enumerable.Range(0, _
            _Items.GetUpperBound(0)).Any(Function(x As Integer) value.GetValue(x) _
            IsNot _Items.GetValue(x))) Then
                _Items = value
                If _CurrentIndex > _Items.GetUpperBound(0) _
                            Then _CurrentIndex = _Items.GetUpperBound(0)
                PctCurrentItem.Invalidate()
            End If
        End Set
    End Property
    
    ''' <summary>Index of Current Item</summary>
    Private _CurrentIndex As Integer = 0
    ''' <summary>Index of Current Item</summary>
    <System.ComponentModel.Browsable(True)>
    <System.ComponentModel.DefaultValue(0)>
    Public Property CurrentIndex As Integer
        Get
            Return _CurrentIndex
        End Get
        Set(value As Integer)
            If value < 0 Then value = 0
            If value > _Items.GetUpperBound(0) Then value = _Items.GetUpperBound(0)
            If value <> _CurrentIndex Then
                _CurrentIndex = value
                PctCurrentItem.Invalidate()
                RaiseEvent CurrentIndexChanged(Me, New EventArgs)
            End If
        End Set
    End Property
    ''' <summary>Text of Current Item</summary>
    Public ReadOnly Property CurrentItem As Object
        Get
            If _CurrentIndex >= 0 AndAlso _CurrentIndex <= Items.GetUpperBound(0) _
                      Then Return Items.GetValue(_CurrentIndex) Else Return Nothing
        End Get
    End Property
    

    我尝试让属性添加了Browsable属性和一个默认值,以允许通过属性面板进行编辑。我不能把一个默认值的项目属性。我第一次将项目作为字符串数组放入,但我意识到,如果项目可以是任何类型对象(例如statepattern)的数组,并显示字符串表示,那么它可能更有用。这使得默认值不存在,并且属性面板中的元素更难(或不可能)可编辑性,但我认为这样更好。如果项目属性是不可浏览的,可能会更好。 CurrentIndex的变化引发了currentindexchangeevent。我做了所有引用当前指数代码通过_CurrentIndex字段,但是当它将,我使用属性使代码快(我工作的方法:如果是如此棘手,我使用内部代码的得到我想要的是管理,我使用了字段时)和智能(当我想要,我想要提出的事件)。 对用户交互 隐藏,收缩,复制Code

    ''' <summary>Store the Y coordinate of Mouse Down
    ''' (to recognize if it's a drag or a click)</summary>
    Private LastMouseDownY As Integer
    ''' <summary>The control is performing a drag selection</summary>
    Private IsDragging As Boolean
    ''' <summary>Store the Y coordinate of Start of the Drag Action
    ''' (it different from LastMouseDownY: there is a threshold)</summary>
    Private StartDragYLocation As Integer
    ''' <summary>Multiplier minimum of the Drag Action:
    ''' it's value is for the 25% of the screen height, its maximum value is 3,
    ''' it's minimum value is 1</summary>
    Private MinDragMultiplier As Single
    ''' <summary>Multiplier maximum of the Drag Action:
    ''' its value makes the drag of the all screen height is
    ''' over the all list scrolling</summary>
    Private MaxDragMultiplier As Single
    ''' <summary>Shift amount of the Drag</summary>
    Private CurrentDragYAmount As Integer
    ''' <summary>Current Picture Top: I don't know if the action is
    ''' started from the picture, from the entire control.
    ''' I store the location of the control into the screen</summary>
    Private PictureContentCurrentTop As Integer
    ''' <summary>List Picture Top: I don't know if the action is started from the picture,
    ''' from the entire control. I store the location of the control into the screen
    ''' </summary>
    Private PictureListCurrentTop As Integer
    ''' <summary>Number of elements into the drag panel</summary>
    Private MaxItemCountHeightInPanel As Integer = 7
    
    ''' <summary>Mouse down: Store the current Y</summary>
    Private Sub PctCurrentItem_MouseDown(sender As Object, e As MouseEventArgs) _
         Handles Me.MouseDown, PctCurrentItem.MouseDown
        If Not IsDragging AndAlso e.Button = Windows.Forms.MouseButtons.Left Then
            Me_Resize(Nothing, Nothing)
            LastMouseDownY = Me.PointToClient(Control.MousePosition).Y
        End If
        'in any case: switch off the popup
        IsDragging = False
        If PopUpD.Visible Then PopUpD.Close()
    End Sub
    ''' <summary>MouseUp: If I'm not dragging, select the previous or next element</summary>
    Private Sub PctCurrentItem_MouseUp(sender As Object, e As MouseEventArgs) _
          Handles Me.MouseUp, PctCurrentItem.MouseUp
        If Not IsDragging AndAlso e.Button = _
          Windows.Forms.MouseButtons.Left AndAlso _Items.GetUpperBound(0) >= 0 Then
            If LastMouseDownY <= PctCurrentItem.Top + PctCurrentItem.Height * 0.2F Then
                CurrentIndex = If(_CurrentIndex = 0, Items.GetUpperBound(0), _CurrentIndex - 1)
                AnimationDirectionIsUp = True
            ElseIf LastMouseDownY >= PctCurrentItem.Top + PctCurrentItem.Height * 0.8F Then
                CurrentIndex = If(_CurrentIndex = Items.GetUpperBound(0), 0, _CurrentIndex + 1)
                AnimationDirectionIsUp = False
            Else
                Exit Sub
            End If
            ' Start the animation
            AnimationStartTime = Now
            Tmr_Tick(Nothing, Nothing)
        End If
    End Sub
    ''' <summary>If I'm out of the threshold, performs dragging start
    ''' (show the popup)</summary>
    Private Sub PctCurrentItem_MouseMove(sender As Object, e As MouseEventArgs) _
        Handles Me.MouseMove, PctCurrentItem.MouseMove
        If e.Button = Windows.Forms.MouseButtons.Left _
            AndAlso Not IsDragging _
            AndAlso (Me.PointToClient(Control.MousePosition).Y - LastMouseDownY > 5 _
            OrElse Me.PointToClient(Control.MousePosition).Y - LastMouseDownY < -5) _
            AndAlso _Items.GetUpperBound(0) >= 0 Then
            ' Drag start: Shows the panel, with a maximum height as the 80% of the
            ' screen height, with 7 elements (if the item has seven elements)
            IsDragging = True
            Dim PanelHeight As Integer = PctCurrentItem.Height * _
                If(Items.GetUpperBound(0) < MaxItemCountHeightInPanel, _
                Items.GetUpperBound(0) + 1, MaxItemCountHeightInPanel)
            If PanelHeight > My.Computer.Screen.WorkingArea.Height * 0.8F _
              Then PanelHeight = CInt(My.Computer.Screen.WorkingArea.Height * 0.8F)
            PictureListCurrentTop = CInt(Me.PointToScreen(New Point(0, 0)).Y + _
                    Me.Height / 2.0F - PanelHeight / 2.0F)
            PictureContentCurrentTop = PctCurrentItem.PointToScreen(New Point(0, 0)).Y
            If PictureListCurrentTop < 0 Then PictureListCurrentTop = 0
            If PictureListCurrentTop + PanelHeight > _
                       My.Computer.Screen.WorkingArea.Height - 5 _
                       Then PictureListCurrentTop = My.Computer.Screen.WorkingArea.Height - _
                       PanelHeight - 5
    
            ' Set the multiplier if the screen is too short
            If My.Computer.Screen.WorkingArea.Height * 0.8! > PctCurrentItem.Height * _
                     (Items.GetUpperBound(0) + 1) Then
                MinDragMultiplier = 1
            Else
                MinDragMultiplier = (PctCurrentItem.Height * _
                (Items.GetUpperBound(0) + 1)) / 0.8! / My.Computer.Screen.WorkingArea.Height
            End If
    
            If MinDragMultiplier > 3 Then
                MaxDragMultiplier = ((Items.GetUpperBound(0) + 1) / 2.0! - _
                     My.Computer.Screen.WorkingArea.Height * 0.8! / 6 / _
                     PctCurrentItem.Height) / (My.Computer.Screen.WorkingArea.Height / _
                     4.0! / PctCurrentItem.Height)
                MinDragMultiplier = 3
            Else
                MaxDragMultiplier = MinDragMultiplier
            End If
    
            ' set the popup
            StartDragYLocation = Control.MousePosition.Y
            CurrentDragYAmount = 0
            Dim Sz As New Size(Me.Width, CInt(PanelHeight) + 2)
            PopUpD.MinimumSize = Sz
            PopUpD.MaximumSize = Sz
            PopUpD.Size = Sz
            PopUpHost.Size = Sz
            PctItemList.Size = New Size(Sz.Width - 2, Sz.Height - 2)
    
            ' Show the popup
            PopUpD.Show(Me.PointToScreen(New Point(0, 0)).X - 1, CInt(PictureListCurrentTop))
            Tmr.Start()
        End If
    End Sub
    ''' <summary>Set the location after the show
    ''' (elsewhere, the PctItemList is a pixel downer)</summary>
    Private Sub PopUpD_Opened(sender As Object, e As EventArgs) Handles PopUpD.Opened
        PctItemList.Location = New Point(1, 1)
    End Sub
    

    鼠标向下只存储鼠标单击的当前Y位置。它还重置了拖动事件。 如果没有拖动,则鼠标向上执行更改选择。如果指针指向上区域或下区域,它将被选择上一个/下一个元素。它会通过定时器制作的动画来显示。 在MouseMove中,我设置了一个阈值,看看用户是否在执行拖拽到PctCurrentItem_MouseMove: 隐藏,复制Code

    Me.PointToClient(Control.MousePosition).Y - LastMouseDownY > 5 _
         OrElse Me.PointToClient(Control.MousePosition).Y - LastMouseDownY < -5

    如果通过了阈值,它将计算项目列表面板的位置和高度、拖动倍率(见下面)以及弹出面板的大小。然后它显示弹出面板,并让计时器开始执行操作。当弹出窗口显示时,带有项目列表的图片被放置在其中。 我使用了一个倍增器,以确保拖动不会直接增加鼠标移动量,但这是直接成比例的。如果元素的总高度小于屏幕高度的80%(在一个手势中滚动整个列表),则拖动和滚动的量是相同的。如果元素的总高度大于屏幕高度的80%,则拖拽倍增器将把所有列表滚动到屏幕高度的80%。第二次,我意识到如果元素真的很多,直接乘法器不是很容易使用。所以我创建了一个MinDragMultiplier和一个MaxDragMultiplier,它们分别是: 如果整个列表的大小高度的3倍少80%屏幕高度,他们有价值,在其他地方,MinDragMultiplier值为3,另一个执行整个滚动列表的值为40%的屏幕高度,让DragMultiplier像图: 隐藏,复制Code

    ''' <summary>Permits to use Up and Down keys to select the previous/next element</summary>
    ''' <paramname="KeyData">Up and Down keys</param>
    ''' <returns>True</returns>
    Protected Overrides Function IsInputKey(KeyData As Keys) As Boolean
        Return KeyData = Keys.Escape OrElse KeyData = Keys.Up OrElse KeyData = Keys.Down
    End Function
    ''' <summary>Esc: Disable the dragging popup - Up/Down arrows:
    ''' Select the Previous/Next element</summary>
    Private Sub Me_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown
        If IsDragging AndAlso e.KeyCode = Keys.Escape Then
            PopUpD.Close()
            IsDragging = False
            Tmr.Stop()
            e.Handled = True
        ElseIf Not IsDragging AndAlso e.KeyCode = Keys.Up Then
            LastMouseDownY = 0
            PctCurrentItem_MouseUp(Me, New MouseEventArgs_
                  (Windows.Forms.MouseButtons.Left, 1, 0, 0, 0))
            e.Handled = True
        ElseIf Not IsDragging AndAlso e.KeyCode = Keys.Down Then
            LastMouseDownY = Me.Height
            PctCurrentItem_MouseUp(Me, New MouseEventArgs_
                  (Windows.Forms.MouseButtons.Left, 1, 0, Me.Height, 0))
            e.Handled = True
        End If
    End Sub
    

    我还可以用向上和向下键箭头来选择上一个/下一个元素(它们被设置为输入键,在其他地方窗口窗体执行焦点以转到上一个/下一个控件) 此外,Esc键执行关闭弹出窗口,而不执行鼠标选择在绘图期间。当鼠标左键仍在按下时,它将被检查。 关于渲染区域 隐藏,收缩,复制Code

    ''' <summary>DateTime of the start of the animation</summary>
    Private AnimationStartTime As Date
    ''' <summary>Animation Direction (True: Up - False: Down)</summary>
    Private AnimationDirectionIsUp As Boolean
    ''' <summary>Actual  Step of the animation (0-1)</summary>
    Private AnimationStep As Single
    ''' <summary>Timer: If the DragDrop is open:
    ''' Performs the list refresh checking for the mouse position.
    ''' If the DragDrop is closed, it performs the Current shifting</summary>
    Private Sub Tmr_Tick(sender As Object, e As EventArgs) Handles Tmr.Tick
        If IsDragging Then
            If Control.MouseButtons = Windows.Forms.MouseButtons.Left Then
                ' It's still dragging
                Dim DragMultiplier As Single = MaxDragMultiplier
                If DragMultiplier > MinDragMultiplier Then
                    If (StartDragYLocation - Control.MousePosition.Y) / _
                        My.Computer.Screen.WorkingArea.Height < 0.25 _
                        AndAlso (Control.MousePosition.Y - StartDragYLocation) / _
                        My.Computer.Screen.WorkingArea.Height < 0.25 Then
                        DragMultiplier = MinDragMultiplier
                    ElseIf (StartDragYLocation - Control.MousePosition.Y) / _
                        My.Computer.Screen.WorkingArea.Height > 0.5 _
                        OrElse (Control.MousePosition.Y - StartDragYLocation) / _
                        My.Computer.Screen.WorkingArea.Height > 0.5 Then
                        DragMultiplier = MaxDragMultiplier
                    Else
                        DragMultiplier = MinDragMultiplier + _
                              (MaxDragMultiplier - MinDragMultiplier) * _
                              (CSng(Math.Abs(StartDragYLocation - Control.MousePosition.Y)) / _
                              My.Computer.Screen.WorkingArea.Height - 0.25!) * 4
                    End If
                End If
                Dim TmpCurrenty As Integer = _
                       CInt((StartDragYLocation - Control.MousePosition.Y) * DragMultiplier)
                If CurrentDragYAmount <> TmpCurrenty _
                       Then CurrentDragYAmount = TmpCurrenty : PctItemList.Invalidate()
            Else
                ' Stop to drag. Calculates the new Current Index and close the popup
                Dim NewItem As Double = _CurrentIndex + _
                          CurrentDragYAmount / PctCurrentItem.Height
                While NewItem < -0.5 : NewItem += _Items.GetUpperBound(0) + 1 : End While
                While NewItem > _Items.GetUpperBound(0) + 0.5 : _
                          NewItem -= _Items.GetUpperBound(0) + 1 : End While
                CurrentIndex = CInt(NewItem)
                PopUpD.Close()
                IsDragging = False
                Tmr.Stop()
            End If
        Else
            ' It's animating
            Dim TmpAnimationStep As Single = CSng((Now - AnimationStartTime).TotalSeconds * 4)
            If TmpAnimationStep >= 1 Then
                ' End of animation
                AnimationStep = 0
                PctCurrentItem.Invalidate()
                Tmr.Stop()
            Else
                AnimationStep = (1 - TmpAnimationStep) * If(AnimationDirectionIsUp, -1, 1)
                Tmr.Start()
            End If
            PctCurrentItem.Invalidate()
        End If
    End Sub
    

    咯定时器有两个不同的功能:如果用户选择前一个/下一个元素(通过点击进入上/下区域或通过按上下键箭头,IsDragging字段是假的),它执行一个动画显示选择改变(设置一个AnimationStep和失效的图片,然后油漆事件执行动画)或控件交互列表:如果鼠标左键仍压,计算实际的列表位置通过DragMultiplier如上所示,CurrentDragYAmount是当前项之间的距离位置PctCurrentItem和当前项位置显示PctItemList,如果鼠标不是仍然按下,执行新项目选择。 隐藏,收缩,复制Code

    ''' <summary>If there is an animation: paint the current element and the previous
    ''' (if the animation is to the next) or the next (if the animation is to the previous)
    ''' </summary>
    Private Sub PnlCurrentItem_Paint(sender As Object, e As PaintEventArgs) _
             Handles PctCurrentItem.Paint
        If _CurrentIndex >= 0 AndAlso _CurrentIndex <= Items.GetUpperBound(0) Then
            Dim Str As String = Items.GetValue(_CurrentIndex).ToString(), _
              SizeStr As SizeF = e.Graphics.MeasureString(Str, PctCurrentItem.Font)
            If AnimationStep = 0 Then
                ' No animations: draw the current element
                e.Graphics.DrawString(Str, PctCurrentItem.Font, _
                     New SolidBrush(Me.ForeColor), _
                     CInt(PctCurrentItem.Width / 2 - SizeStr.Width / 2), 1)
            Else
                ' Animations: Draw two elements
                e.Graphics.DrawString(Str, PctCurrentItem.Font, _
                    New SolidBrush(Me.ForeColor), _
                    CInt(PctCurrentItem.Width / 2 - SizeStr.Width / 2), _
                    1 + AnimationStep * SizeStr.Height)
                Dim Indx As Integer = _CurrentIndex + If(AnimationDirectionIsUp, 1, -1)
                If Indx < 0 Then
                    Indx = Items.GetUpperBound(0)
                ElseIf Indx > Items.GetUpperBound(0) Then
                    Indx = 0
                End If
                Str = Items.GetValue(Indx).ToString()
                SizeStr = e.Graphics.MeasureString(Str, PctCurrentItem.Font)
                e.Graphics.DrawString(Str, PctCurrentItem.Font, _
                     New SolidBrush(Me.ForeColor), _
                     CInt(PctCurrentItem.Width / 2 - SizeStr.Width / 2), _
                     1 + AnimationStep * SizeStr.Height + PctCurrentItem.Height * _
                     If(AnimationDirectionIsUp, 1, -1))
            End If
        End If
        If Not Me.Enabled Then e.Graphics.FillRectangle(New SolidBrush_
               (Color.FromArgb(128, 255, 255, 255)), 0, 0, PctCurrentItem.Width, _
               PctCurrentItem.Height)
    End Sub
    

    CurrentItem的绘制执行动画帧(如果动画正在运行),或者显示当前项。如果控件被禁用,最后一行将执行衰落。 隐藏,收缩,复制Code

    ''' <summary>Draw the list of all items. It's made two times
    ''' (if the list is to draw from one of latest) according to the animation</summary>
    Private Sub PctItemList_Paint(sender As Object, e As PaintEventArgs) _
         Handles PctItemList.Paint
        If IsDragging Then
            Dim CurrentY As Integer = PictureContentCurrentTop - _
                PictureListCurrentTop - _CurrentIndex * PctCurrentItem.Height - _
                CurrentDragYAmount, Str As String, SizeStr As SizeF
            While CurrentY > 0 : CurrentY -= PctCurrentItem.Height * _
                  (_Items.GetUpperBound(0) + 1) : End While
            While CurrentY < -PctCurrentItem.Height * _
               (_Items.GetUpperBound(0) + 1) : CurrentY += PctCurrentItem.Height * _
               (_Items.GetUpperBound(0) + 1) : End While
            For I As Integer = 0 To 1
                For J As Integer = 0 To Items.GetUpperBound(0)
                    If CurrentY > -PctCurrentItem.Height AndAlso CurrentY < _
                        PctItemList.Height Then
                        Str = Items.GetValue(J).ToString()
                        SizeStr = e.Graphics.MeasureString(Str, Me.Font)
                        e.Graphics.DrawString(Str, Me.Font, _
                               New SolidBrush(Me.ForeColor), _
                               CInt(Me.Width / 2 - SizeStr.Width / 2), CurrentY)
                    End If
                    CurrentY += PctCurrentItem.Height
                Next J
            Next I
            e.Graphics.DrawRectangle(New Pen(Color.FromArgb(64, 0, 0, 0)), 0, _
                  PictureContentCurrentTop - PictureListCurrentTop, _
                  PctItemList.Width - 1, PctCurrentItem.Height)
        End If
    End Sub
    

    在拖动过程中,计时器会使ItemList失效,看起来像是滚动的动画。实际上,只绘制那些在可见区域可见的元素。 如果它计算上面的项来显示和当前位置会更有效率,但是今天我很懒。: -) 最后:箭画: 隐藏,复制Code

    ''' <summary>Draw arrow buttons</summary>
    Private Sub Me_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
        Dim SizeArrow As Single = PctCurrentItem.Top - 1
        Dim ArrowWidth As Single = SizeArrow / 4
        e.Graphics.DrawLines(New Pen(ArrowColor, ArrowWidth * _ArrowWidth), _
           {New PointF(Me.Width / 2.0F - SizeArrow * 2, SizeArrow), _
           New PointF(Me.Width / 2.0F, 0), New PointF(Me.Width / 2.0F + _
           SizeArrow * 2, SizeArrow)})
        e.Graphics.DrawLines(New Pen(ArrowColor, ArrowWidth * _ArrowWidth), _
           {New PointF(Me.Width / 2.0F - SizeArrow * 2, Me.Height - SizeArrow), _
           New PointF(Me.Width / 2.0F, Me.Height - 0), New PointF(Me.Width / 2.0F + _
           SizeArrow * 2, Me.Height - SizeArrow)})
        If Me.Focused Then e.Graphics.DrawRectangle(New Pen(SystemColors.Highlight) _
           With {.DashStyle = Drawing2D.DashStyle.Dash}, 0, 0, Me.Width - 1, Me.Height - 1)
        If Not Me.Enabled Then e.Graphics.FillRectangle(New SolidBrush_
           (Color.FromArgb(128, 255, 255, 255)), 0, 0, Me.Width, Me.Height)
    End Sub
    

    和控制定位时,会有一个大小调整: 隐藏,复制Code

    ''' <summary>Resize the picture of the current item</summary>
    Private Sub Me_Resize(sender As Object, e As EventArgs) Handles Me.Resize
        PctCurrentItem.Left = 1
        PctCurrentItem.Width = Me.Width - 2
        PctCurrentItem.Top = (Me.Height - PctCurrentItem.Height) \ 2
        Me.Invalidate()
    End Sub
    

    使用控制 ItemList可以通过一个简单的赋值设置。设置闹钟的时间,你可以做两种序列: 隐藏,复制Code

    DlcHour.Items = New String() {"00 am", "01 am", "02 am", [...] "11 am", "12 pm", "01 pm", .. }

    或者: 隐藏,复制Code

    DlcHour.Items = Enumerable.Range(0, 24).Select(Function(x As Integer) x.ToString("00")).ToArray()

    设置StatePattern数组: 隐藏,复制Code

    DlcSetUp.Items = New Object () {StatePattern1, StatePattern2, StatePattern3}

    要拦截用户选择,可以使用currentindexchangeevent。 在附加的示例中,我指出了使用该控件的一些不同方法。我用它从字符串数组中选择一个元素: 隐藏,复制Code

    DLCString.Items = {"First Element", "Second Element", "Third Element", "Fourth Element"}

    一个整数数组: 隐藏,复制Code

    DLCAThousand.Items = Enumerable.Range(0, 1000).ToArray()

    格式化数字数组: 隐藏,复制Code

    DLCMinutes.Items = Enumerable.Range(0, 60).Select(Function(x) x.ToString("00")).ToArray()

    枚举值数组: 隐藏,复制Code

    DLCObjects1.Items = [Enum].GetValues(GetType(FormBorderStyle))

    和一个对象数组: 隐藏,复制Code

    Private Class AClass
        Public Property Descr As String
        Public Property Value As Color
        Public Overrides Function ToString() As String
            Return Descr
        End Function
    End Class
    Dim MyArray As AClass() = {New AClass With {.Descr = "Red", .Value = Color.Red},
                               New AClass With {.Descr = "Green", .Value = Color.Green},
                               New AClass With {.Descr = "Blue", .Value = Color.Blue},
                               New AClass With {.Descr = "Yellow", .Value = Color.Yellow}}
    [...]
    DLCObjects2.Items = MyArray
    

    有数千个元素的控制,你可以看到加速度斜坡的效果。如果您想选择一个near元素,选择起来很容易。如果你想选择一个远的元素,你必须在这个近的范围内。 选择的效果会显示在事件拦截器中: 隐藏,复制Code

    Private Sub DLCString_CurrentIndexChanged(sender As Object, e As EventArgs) _
        Handles DLCString.CurrentIndexChanged
        Me.Text = DLCString.CurrentItem.ToString()
    End Sub
    Private Sub DLCObjects1_CurrentIndexChanged(sender As Object, e As EventArgs) _
        Handles DLCObjects1.CurrentIndexChanged
        Me.FormBorderStyle = CType(DLCObjects1.CurrentItem, FormBorderStyle)
    End Sub
    Private Sub DLCObjects2_CurrentIndexChanged(sender As Object, e As EventArgs) _
        Handles DLCObjects2.CurrentIndexChanged
        Me.BackColor = CType(DLCObjects2.CurrentItem, AClass).Value
    End Sub
    

    的兴趣点 可能需要将列表上方和下方的元素创建为真正的按钮。他们的表现就不那么可爱了。我并没有过多地关注它们。 我想在WPF中创建这个控件,但我没有做到。我想看看能够做到的人是如何做到的。 我想在一个DateTimePicker控件替换年和月像这样的控件: → 我不知道这是否可能(我认为如果我想把年度控制分成两个不同的部分,一年和一天,那就不简单了)。 本文转载于:http://www.diyabc.com/frontweb/news360.html

  • 相关阅读:
    scp上传服务器文件
    svn一次添加所有未添加的文件
    vue 去掉#和拼接参数
    vuex状态管理
    获取页面iframe里的元素
    angular 中ng-bind-html 、$scope服务
    心态崩了
    day 8
    day 7
    day6 angularjs学习
  • 原文地址:https://www.cnblogs.com/Dincat/p/13443802.html
Copyright © 2011-2022 走看看