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
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
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
PositionIndicator(r)
Else
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
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.