Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / VB

ProgressBar with Percentage

4.48/5 (23 votes)
3 Nov 2009GPL33 min read 182.8K   11.5K  
Component that extends the native .NET progress bar with percentage properties and the ability to display it in the progress bar.
pbarWithPercentageDemo.gif pbarWithPercentageDemo.gif

Introduction

This class extends the native .NET progress bar with a percentage property that can be displayed inside the progress bar, and is used to get or set the value of the bar itself. The text can be aligned with the Alignment property and also has Font and Padding properties to allow further customization. On top of this, you can change the color of the percentage that is in the colored part of the progress bar.

Why ANOTHER progress bar control, you might ask yourself. Simple. Before creating this control, I did quite some research into finding a control that enabled displaying a percentage in a progress bar. Most of them succeeded in doing this with varying degrees of customization options, and worked fine in Windows XP. However, once using it on a Vista, the percentage would get deleted because the bar continuously redraws itself. This control will automatically redraw the percentage when the bar is refreshed.

Background

This class contains a lot of code based upon work by people on VB.NET forums. Go to this thread for more information. I am using this component in multiple VB.NET applications without any problems, and it should work in projects in other .NET languages.

Using the Code

Once you added the class to your project, you should be able to add the new component to your forms with the designer or do it manually with code.

Here you have an overview of properties that have been added:

VB.NET
<Browsable(True), Category("Appearance"), _
	Description("The percentage of the progressbar")> _
Public Property Percentage() As Double
    Get
        Return Me.Value / Me.Maximum * 100
    End Get
    Set(ByVal value As Double)
        If value >= 0 And value <= 100 Then
            Me.Value = CInt(Me.Maximum * value / 100)
            If Me.PercentageVisible And Me.AutoUpdatePercentage _
			Then Me.ShowPercentage()
        End If
    End Set
End Property
VB.NET
<Browsable(True), Category("Appearance"), DefaultValue(0), _
	Description("Gets or sets the amount of decimals that will _
	be displayed in the percentage")> _
Public Overridable Property PercentageDecimals() As Int32
    Get
        Return m_decimals
    End Get
    Set(ByVal value As Int32)
        If value > -1 Then m_decimals = value
    End Set
End Property
VB.NET
<Browsable(True), Category("Appearance"), DefaultValue(True), _
	Description("Gets or sets if the percentage should be visible")> _
Public Overridable Property PercentageVisible() As Boolean
    Get
        Return m_p_visible
    End Get
    Set(ByVal value As Boolean)
        If value <> Me.PercentageVisible Then
            If Not value Then Me.Graphics.Clear(Color.Transparent)
            m_p_visible = value
            RaiseEvent PercentageVisibleChanged(Me, New EventArgs)
        End If
    End Set
End Property
VB.NET
<Browsable(True), Category("Appearance"), DefaultValue("MiddleCenter"), _
	Description("Gets or sets if the percentage alignment")> _
Public Overridable Property PercentageAlign() As ContentAlignment
    Get
        Return m_p_align
    End Get
    Set(ByVal value As ContentAlignment)
        m_p_align = value
    End Set
End Property
VB.NET
<Browsable(True), Category("Appearance"), _
	Description("Gets or sets the color of the percentage text _
	at the place of the progressbar that is indicated")> _
Public Overridable Property OverLayColor() As Color
    Get
        Return m_overLayFont
    End Get
    Set(ByVal value As Color)
        m_overLayFont = value
    End Set
End Property
VB.NET
<Browsable(True), Category("Behavior"), DefaultValue(True), _
	Description("Gets or sets if the percentage should be auto updated")> _
Public Overridable Property AutoUpdatePercentage() As Boolean
    Get
        Return m_auto_update
    End Get
    Set(ByVal value As Boolean)
        m_auto_update = value
    End Set
End Property
VB.NET
<Browsable(True), Category("Layout"), _
	Description("Gets or sets if the interior spacing of the control")> _
Public Overridable Overloads Property Padding() As Padding
    Get
        Return MyBase.Padding
    End Get
    Set(ByVal value As Padding)
        MyBase.Padding = value
    End Set
End Property
VB.NET
<Browsable(True), Category("Appearance"), _
	Description("Gets or sets the font of the percentage text")> _
Public Overridable Overloads Property Font() As Font
    Get
        Return MyBase.Font
    End Get
    Set(ByVal value As Font)
        MyBase.Font = value
    End Set
End Property

Example

A simple example of setting a few properties:

VB.NET
With Me.ProgressbarWithPercentage1
    .ForeColor = Drawing.Color.DimGray ' Color of the text not in the colored part
    .OverLayColor = Drawing.Color.Black ' Color of the text in the colored part
    .PercentageAlign = Drawing.ContentAlignment.MiddleLeft ' Alignment of the text
    .Padding = New Windows.Forms.Padding(20, 0, 0, 0) ' Padding of the text
End With

progbarwithpercentage.gif

Inside the Component

Now how does it actually work? I'll try to give you a reasonable understanding.

The most important method is the ShowText method, which draws a string onto the progress bar. This method can be used to draw any string, but is internally only used to draw the percentage.

VB.NET
Public Sub ShowText(ByVal text As String)
    ' Determine the areas for the ForeColor and OverlayColor
    Dim r1 As RectangleF = Me.ClientRectangle
    r1.Width = CSng(r1.Width * Me.Value / Me.Maximum)
    Dim reg1 As New Region(r1)
    Dim reg2 As New Region(Me.ClientRectangle)
    reg2.Exclude(reg1)

    ' Draw the string
    Me.Graphics.Clip = reg1
    Me.Graphics.DrawString(text, Me.Font, New SolidBrush(Me.OverLayColor), _
		Me.DrawingRectangle, m_strFormat)
    Me.Graphics.Clip = reg2
    Me.Graphics.DrawString(text, Me.Font, New SolidBrush(Me.ForeColor), _
	Me.DrawingRectangle, m_strFormat)

    reg1.Dispose()
    reg2.Dispose()
End Sub

This method is used by the ShowPercentage method in a pretty straight forward way:

VB.NET
Public Sub ShowPercentage()
    Me.ShowText(Math.Round(Me.Percentage, _
	Me.PercentageDecimals).ToString & "%")
End Sub

The rectangle to draw in is determined every time the control is resized and every time the padding is changed with the following code:

VB.NET
Private Sub setDrawingRectangle()
    ' Determine the coordinates and size of the drawing rectangle
	' depending on the progress bar size and padding
    Me.DrawingRectangle = New RectangleF(Me.Padding.Left, _
                                       Me.Padding.Top, _
                                       Me.Width - Me.Padding.Left - Me.Padding.Right, _
                                       Me.Height - Me.Padding.Top - Me.Padding.Bottom)
        End Sub

Note that this property is used for every draw event. Another property used for every draw event is the stringformat. This is set every time you change the alignment.

VB.NET
Private Sub setStringFormat()
    ' Determine the horizontal alignment
    Select Case Me.PercentageAlign
        Case ContentAlignment.BottomCenter, _
		ContentAlignment.BottomLeft, ContentAlignment.BottomRight
                    m_strFormat.LineAlignment = StringAlignment.Far
        Case ContentAlignment.MiddleCenter, _
		ContentAlignment.MiddleLeft, ContentAlignment.MiddleRight
                    m_strFormat.LineAlignment = StringAlignment.Center
        Case ContentAlignment.TopCenter, _
		ContentAlignment.TopLeft, ContentAlignment.TopRight
                    m_strFormat.LineAlignment = StringAlignment.Near
    End Select

    ' Determine the vertical alignment
    Select Case Me.PercentageAlign
        Case ContentAlignment.BottomLeft, _
		ContentAlignment.MiddleLeft, ContentAlignment.TopLeft
                    m_strFormat.Alignment = StringAlignment.Near
        Case ContentAlignment.BottomCenter, _
		ContentAlignment.MiddleCenter, ContentAlignment.TopCenter
                    m_strFormat.Alignment = StringAlignment.Center
        Case ContentAlignment.BottomRight, _
		ContentAlignment.MiddleRight, ContentAlignment.TopRight
                    m_strFormat.Alignment = StringAlignment.Far
    End Select
End Sub

History

Changes in version 1.0.10

  • Added percentage format property, allowing you to use custom formats
  • Fixed XP bug, that caused the percentage not to be displayed properly
  • Created SourceForge project for SVN capabilities

Changes in version 1.0.9

  • Fixed a number of dispose issues (a LOT of thanks to JohnH for helping me with this!)
  • Fixed bug in percentage calculation when using multiple decimals
  • Added an auto increment function to the demo and added decimals to a few bars

Changes in version 1.0.6

  • Improved component efficiency by not recalculating some values for every draw event
  • Added multiple new events

Changes in version 1.0.5

  • Added extra documentation and events

Changes in version 1.0.4

  • Fixed alignment bug
  • Added padding property

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)