65.9K
CodeProject 正在变化。 阅读更多。
Home

永不停止的进度条

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.36/5 (33投票s)

2004年9月30日

CPOL

2分钟阅读

viewsIcon

235723

downloadIcon

1342

一个用于您不知道过程需要多长时间的进度条。

Sample screenshot

引言

有时候你就是不知道事情会持续多久。 就像你妻子说她只会在杂货店待几分钟... 你懂我的意思。

Visual Studio 附带的标准ProgressBar对于您知道某事需要多长时间或者可以确定一个过程有多少步骤的情况非常有用。 但就像你和你妻子去商店一样,有时你就是不知道事情会持续多久。 这就是我创建这个进度条的原因。

代码

该控件非常简单,它所做的就是使用标准Graphics方法绘制到一个Rectangle对象中。

Private Sub OSProgressBar_Paint(ByVal sender As Object, _
         ByVal e As System.Windows.Forms.PaintEventArgs) _
         Handles MyBase.Paint
    Me._Graphics = e.Graphics
    Me._Graphics.SmoothingMode = Drawing2D.SmoothingMode.HighSpeed

    'this stops some of the redraw flickering at higher speeds
    If _RequireClear Then
        Me._Graphics.Clear(Me.BackColor)
    End If

    DrawBackGround()
End Sub

Private Sub PositionIndicator(ByVal Rect As Rectangle)
    If Not IsNothing(Me._PointImage) AndAlso Me._ProgressType = _
                        OSProgressTypeConstants.osGRAPHICTYPE Then
        Me._Graphics.DrawImage(Me._PointImage, Rect)
    Else
        Select Case Me._ProgressBoxStyle
            Case OSProgressBoxStyleConstants.osSOLIDSAMESIZE
                Dim R2 As New Rectangle(Rect.Left + 3, _
                  Rect.Top + 3, Rect.Width - 5, Rect.Height - 5)
                Me._Graphics.FillRectangle(New SolidBrush(_IndicatorColor), R2)
            Case OSProgressBoxStyleConstants.osBOXAROUND
                Me._Graphics.DrawRectangle(New Pen(_IndicatorColor), Rect)
                Dim R2 As New Rectangle(Rect.Left + 3, Rect.Top + 3, _
                                        Rect.Width - 5, Rect.Height - 5)
                Me._Graphics.FillRectangle(New SolidBrush(_IndicatorColor), R2)
            Case OSProgressBoxStyleConstants.osSOLIDBIGGER
                Me._Graphics.FillRectangle(New SolidBrush(_IndicatorColor), Rect)
            Case OSProgressBoxStyleConstants.osSOLIDSMALLER
                Dim R2 As New Rectangle(Rect.Left + 5, Rect.Top + 5, _
                                        Rect.Width - 9, Rect.Height - 9)
                Me._Graphics.FillRectangle(New SolidBrush(_IndicatorColor), R2)
        End Select
    End If
End Sub

Private Sub DrawBackGround()
    Me._NumPoints = 0
    If Me.Width > 0 And Me.Height > 0 Then
        If Me._ShowBorder Then
            Me._Graphics.DrawRectangle(New Pen(SystemColors.ActiveBorder), _
                    New Rectangle(0, 0, Me.Width - 1, Me.Height - 1))
        End If
        Dim iBoxSize As Integer = Me.Height * 0.75
        Dim iBoxLeft As Integer = iBoxSize / 2
        If iBoxSize > 3 Then
            Do
                'entire area Rectangle for the background image
                Dim r As New Rectangle(iBoxLeft, 0, Me.Height - 1, Me.Height - 1)
                If r.Left + r.Width > Me.Width Then
                    Exit Do
                End If
                If Me._NumPoints = Me._Position Then
                    'draw position indicator in full rectagle
                    PositionIndicator(r)
                Else
                    'this will be the rectangle where 
                    'the background image is drawn
                    Dim R2 As New Rectangle(r.Left + 3, r.Top + 3, _
                                            r.Width - 6, r.Height - 6)
                    If Not IsNothing(Me._NormalImage) AndAlso Me._ProgressType = _
                                  OSProgressTypeConstants.osGRAPHICTYPE Then
                        Me._Graphics.DrawImage(Me._NormalImage, R2)
                    Else
                        Me._Graphics.FillRectangle(New SolidBrush(Me.ForeColor), R2)
                    End If
                End If
                iBoxLeft += (iBoxSize * 1.5)
                Me._NumPoints += 1
            Loop
        End If
    End If
End Sub

Private Sub OSProgressBar_Resize(ByVal sender As Object, _
            ByVal e As System.EventArgs) Handles MyBase.Resize
    Me._RequireClear = True
    'invalidate the control
    Me.Invalidate()
End Sub

Private Sub tmrAutoProgress_Tick(ByVal sender As Object, _
       ByVal e As System.EventArgs) Handles tmrAutoProgress.Tick
    If Me._Position = Me._NumPoints - 1 Then
        If Me._ProgressStyle = OSProgressStyleConstants.osLEFTTORIGHT Then
            Me._Position = 0
        Else
            Me._Position -= 1
            Me._Increasing = False
        End If
    ElseIf Me._Position = 0 And Not Me._Increasing Then
        Me._Position += 1
        Me._Increasing = True
    Else
        If Me._Increasing Then
            Me._Position += 1
        Else
            Me._Position -= 1
        End If
    End If
    Me._RequireClear = False
    Me.Invalidate()
End Sub

用户可以选择四种类型中的一种绘制标准方框(与背景框相同大小、更小、更大或带框更小),或者用户可以选择使用图像(图标效果最佳)作为背景和位置指示器。

矩形大小和位置数量由控件放置在表单上的高度决定。 例如,如果控件很高,则矩形会更少,但会更大。 另外,如果它很短,则矩形会更多,更小。 目前,该控件只有在水平(宽度大于高度)时才能正常运行,但我认为修改垂直操作的代码不会太难。

对于方框类型进度条,开发人员可以设置BackGroundColorForeGroundColor(背景框的颜色)、IndicatorColor(位置框的颜色)。 对于图形类型进度条,可以设置NormalImage(背景图像)和PointImage(位置图像)图像。

开发人员可以确定控件是否“自动前进”,也就是说,如果它自动更改位置直到开发人员停止它。 如果启用了AutoProgress,则还会用到另外两个属性; AutoProgressSpeedProgressStyle。 速度是不言自明的,1是慢的,255是快的。 ProgressStyle属性确定当指示器到达最后一点时,它是否从第一点开始,或者调头并朝另一个方向前进。 当然,开发人员也可以根据需要手动设置位置。

关于显示进度类型控件的说明。 如果您有一个您无法控制的长时间运行的过程,则当前线程可能会在此过程中被阻塞。 我在序列化和反序列化类时发现了这一点。 在这种情况下,您在同一线程中运行的任何方法也将被阻塞。 我为此尝试过动画 GIF,当阻塞发生时它们也会停止动画。 有必要在调用阻塞函数之前生成一个新线程,然后显示必要的进度指示器。

© . All rights reserved.