Click here to Skip to main content
15,868,141 members
Articles / Programming Languages / Visual Basic
Article

A Never-ending ProgressBar

Rate me:
Please Sign up or sign in to vote.
4.36/5 (37 votes)
30 Sep 2004CPOL2 min read 227.6K   1.3K   100   68
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.

VB
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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
Visual Basic Developer since version 1.0
Java web developer
Currently developing in vb and c#

Comments and Discussions

 
GeneralSuggestion Pin
Ray Cassick1-Jul-08 7:28
Ray Cassick1-Jul-08 7:28 
GeneralRe: Suggestion Pin
Greg Osborne1-Jul-08 10:59
Greg Osborne1-Jul-08 10:59 
GeneralBrilliant! Pin
jeff branscum14-Sep-07 5:34
jeff branscum14-Sep-07 5:34 
GeneralRe: Brilliant! Pin
Greg Osborne14-Sep-07 6:37
Greg Osborne14-Sep-07 6:37 
GeneralUsing with a status form Pin
lozinakr27-Jul-07 9:49
lozinakr27-Jul-07 9:49 
GeneralRe: Using with a status form Pin
Greg Osborne30-Jul-07 5:21
Greg Osborne30-Jul-07 5:21 
GeneralRe: Using with a status form Pin
lozinakr30-Jul-07 5:47
lozinakr30-Jul-07 5:47 
GeneralMay need a separate thread Pin
Jalapeno Bob24-Jul-07 9:21
professionalJalapeno Bob24-Jul-07 9:21 
AnswerRe: May need a separate thread Pin
Greg Osborne24-Jul-07 11:37
Greg Osborne24-Jul-07 11:37 
GeneralRe: May need a separate thread Pin
Greg Osborne30-Jul-07 5:24
Greg Osborne30-Jul-07 5:24 
GeneralLook and feel... Pin
rw_architect13-Jun-07 3:43
rw_architect13-Jun-07 3:43 
GeneralProgress bar only runs once Pin
Njabulo Nxele31-May-07 1:01
Njabulo Nxele31-May-07 1:01 
GeneralRe: Progress bar only runs once Pin
Greg Osborne31-May-07 5:23
Greg Osborne31-May-07 5:23 
GeneralRe: Progress bar only runs once Pin
Njabulo Nxele31-May-07 20:41
Njabulo Nxele31-May-07 20:41 
GeneralRe: Progress bar only runs once Pin
Greg Osborne31-May-07 5:25
Greg Osborne31-May-07 5:25 
GeneralRe: Progress bar only runs once Pin
Njabulo Nxele31-May-07 21:37
Njabulo Nxele31-May-07 21:37 
GeneralRe: Progress bar only runs once Pin
Greg Osborne1-Jun-07 4:42
Greg Osborne1-Jun-07 4:42 
GeneralThanks Pin
ginxs30-May-07 8:10
ginxs30-May-07 8:10 
Questionasp.net or windows Pin
dsmportal10-Apr-07 7:40
dsmportal10-Apr-07 7:40 
QuestionHow do I do.... Pin
Psycho-*Coder*-Extreme17-Jan-07 8:39
Psycho-*Coder*-Extreme17-Jan-07 8:39 
AnswerRe: How do I do.... Pin
Greg Osborne17-Jan-07 9:47
Greg Osborne17-Jan-07 9:47 
GeneralRe: How do I do.... Pin
Psycho-*Coder*-Extreme17-Jan-07 9:59
Psycho-*Coder*-Extreme17-Jan-07 9:59 
QuestionWhat Am I missing? Control does not remotely look like it should Pin
wgkwvl20-Nov-06 23:42
wgkwvl20-Nov-06 23:42 
AnswerRe: What Am I missing? Control does not remotely look like it should Pin
Greg Osborne31-May-07 5:27
Greg Osborne31-May-07 5:27 
GeneralRe: What Am I missing? Control does not remotely look like it should Pin
rw_architect13-Jun-07 3:42
rw_architect13-Jun-07 3:42 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.