Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

A Never-ending ProgressBar

0.00/5 (No votes)
30 Sep 2004 1  
A progress bar for when you don't know how long a process will take.

Sample screenshot

Introduction

Sometimes you just don’t know how long something will take. Like when your wife says she’ll only be a few minutes in the grocery store…you know what I mean.

The standard ProgressBar that ships with Visual Studio is great for when you know how long something will take or there is a way to determine just how many steps a process will have. But like the trip to the store with your wife, sometimes you just can’t know how long something’s going to take. That’s why I created this progress bar.

The code

The control is very simple in that all it does is use the standard Graphics methods to draw into a Rectangle object.

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

The user can choose whether to have the standard boxes drawn in one of four types (same size as background box, smaller, larger, or smaller with a box around), or the user can select to use images (icons work best) for the background and position indicators.

Rectangle size and number of positions are determined by the height of the control when placed on a form. For instance, if the control is tall, there will be fewer rectangles, but they will be larger. Alternately, if it is short, more rectangles and smaller. Currently, the control will only operate properly when horizontal (width is greater than the height), but I don't think the code would be too difficult to modify for vertical operation.

For a box type progress bar, developers can set the BackGroundColor, the ForeGroundColor (color of the background boxes), the IndicatorColor (color of the position boxes). For a graphic type progress bar, NormalImage (background image) and PointImage (position image) images can be set.

Developers can determine if the control "autoprogresses", that is, if it changes position automatically until the developer stops it. If AutoProgress is enabled, two more properties come into play; AutoProgressSpeed and ProgressStyle. The speed is self explanatory, 1 is slow, 255 is fast. The ProgressStyle property determines that when the indicator reaches the last point, if it starts over at the first point, or turns around and heads back in the other direction. Of course, the developer can also set the position manually if so desired.

Just a note concerning display of progress type controls. If you have a long process that you don't control, the current thread may block during the process. I've found this to be so when serializing and deserializing classes. In this instance, any method you use that is running within the same thread will also be blocked. I've tried animated GIFs for this purpose, and they also stop animating when blocking occurs. It's necessary to spawn a new thread prior to calling the blocking function and then display the necessary progress indicator.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here