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

ColorBar - A Gradient Colored ProgressBar

4.62/5 (51 votes)
14 Jun 2008CPOL3 min read 1   6.7K  
ColorBar is a gradient colored progress bar control written using VB.NET.

ColorBar_Sample.JPG

Introduction

ColorBar is a gradient colored progress bar control, written in VB.NET. It was created to add interest to the progress bars in my application.

Using the Code

In your project, add a reference to ColorBar.dll. You may also add the control to the VS toolbox, so you can drag n' drop it on to your form or instantiate it from within your code (this is what the sample application does).

The control is used similar to a regular progress bar control. Set the Minimum and Maximum properties accordingly; then increment the Value property. The Smoothness property controls the coarseness of the gradient from one color to the next.

The BarStyle property can be set to Expand, Flow, or Block. An Expanding bar expands from left to right with all colors in it. A Flowing bar flows from left to right, exposing each color as it goes and, finally, a Block style bar is a flowing bar with 'outset' blocks. The Block style bar (not available in circular orientation) is affected by the width of the control, the number of colors in the color list, and the smoothness of the gradient.

A ColorBar with Minimum Smoothness:

ColorBar_Chunky.JPG

A Block Style ColorBar:

ColorBar_Blocks.JPG

The rainbow colors, ROYGBIV, plus Cyan, are the default colors used in the control. If you wish to use your own colors, simply make a list with a minimum of two colors and assign this list to the ColorList property. To revert to the default list, assign the ColorList property a value of Nothing. A long lists of colors will start to push together and may not look "smooth" in controls of short lengths.

A ColorBar with Custom Colors:

ColorBar_2Color.JPG

A Vertical ColorBar with Default Colors:

ColorBar_Vertical.JPG

A Circular ColorBar with Default Colors and Thickness:

ColorBar_Circular.JPG

A Circular ColorBar with Custom Colors and Thicknesses:

ColorBar_Thickness.JPG

Creating the ColorBar control (from code) is simple and straight-forward:

VB
Dim cb as ColorBar

' instance the control - in Form Load event perhaps
cb = New ColorBar
cb.Size = New Size(300, 18)
cb.Location = New Point((Me.ClientRectangle.Width / 2) - (cb.Size.Width / 2), 50)
cb.Visible = True
cb.Parent = Me
Me.Controls.Add(cb)

' set initial properties
cb.Smoothness = ColorBar.MaxSmoothness
cb.Style = ColorBar.BarStyle.Expand

Adding custom colors is also easy:

VB
' create a list of custom colors
Dim lstColors As New List(Of Color)
lstColors.Add(Color.Red)
lstColors.Add(Color.Green)

' assign to control
cb.ColorList = lstColors

To remove custom colors:

VB
cb.ColorList = Nothing

Points of Interest

This control is double-buffered to avoid flicker:

VB
Me.SetStyle(ControlStyles.AllPaintingInWmPaint Or ControlStyles.UserPaint Or _
            ControlStyles.DoubleBuffer Or ControlStyles.Opaque, True)
Me.UpdateStyles()

The WM_ERASEBKGND message is also ignored in an attempt to avoid flicker:

VB
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
      If m.Msg = &H14 Then ' ignore WM_ERASEBKGND
          Return
      End If
      MyBase.WndProc(m)
End Sub

The interpolated color list is created with the following routines. For every two colors, an interpolated color is found and inserted back in the list.

VB
Private Function InterpolateColors(ByVal color1 As Color, ByVal color2 As Color) As Color
    Return Color.FromArgb(CInt((CInt(color1.R) + CInt(color2.R)) / 2), _
                    CInt((CInt(color1.G) + CInt(color2.G)) / 2), _
                    CInt((CInt(color1.B) + CInt(color2.B)) / 2))
End Function

Private Sub BuildColorList(ByRef lstAdd As List(Of Color))

    lstColors = New List(Of Color)

    Dim c As Color
    For Each c In lstAdd
        lstColors.Add(c)
    Next

    Dim idx As Integer ' lstColors index
    Dim cnt As Integer ' lstColors item count
    Dim sdc As Integer ' sub-divide count

    For sdc = 0 To m_Smoothness Step 1
        idx = 0
        cnt = lstColors.Count - 1
        While idx < cnt
            lstColors.Insert(idx + 1, InterpolateColors(lstColors(idx), _
                             lstColors(idx + 1)))
            idx += 2
            cnt += 1
        End While
    Next sdc

End Sub

Painting the progress bar is done in the OnPaint event. It divides the "completed" rectangle into equal portions for each color.

VB
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)

    e.Graphics.FillRectangle(New SolidBrush(Me.BackColor), Me.ClientRectangle)

    Dim percentComplete As Single = CSng((m_Value - m_Minimum) / _
                                         (m_Maximum - m_Minimum))

    If percentComplete <= 0.0F Then Exit Sub
    If percentComplete > 1.0F Then percentComplete = 1.0F

    Dim fullWidth As Single = CSng(Me.ClientRectangle.Width - BorderWidth)
    Dim totalWidth As Single = fullWidth * percentComplete

    Dim barWidth As Single
    If m_Style = BarStyle.Expand Then
        barWidth = totalWidth
    Else
        If m_Style = BarStyle.Flow Or m_Style = BarStyle.Block Then
            barWidth = fullWidth
        End If
    End If
    barWidth /= CSng(lstColors.Count)

    Dim height As Single = CSng(Me.ClientRectangle.Height - BorderWidth)
    Dim halfBorder As Single = CSng(BorderWidth / 2)
    Dim x As Single = halfBorder
    Dim idxColor As Integer = 0

    For x = halfBorder To totalWidth Step barWidth
        e.Graphics.FillRectangle(New SolidBrush(lstColors(idxColor)), x, _
                                 halfBorder, barWidth, height)
        If barWidth > 4 And Me.Style = BarStyle.Block Then
            ControlPaint.DrawBorder(e.Graphics, New Rectangle(CInt(x), _
                         CInt(halfBorder), CInt(barWidth), CInt(height)), _
                         Color.Gray, ButtonBorderStyle.Outset)
        End If
        If idxColor < lstColors.Count Then
            idxColor += 1
        End If
    Next

    If (x < (Me.ClientRectangle.Width - halfBorder)) And percentComplete = 1.0 Then
        If idxColor < lstColors.Count Then
            e.Graphics.FillRectangle(New SolidBrush(lstColors(idxColor)), x, halfBorder, _
                     ((Me.ClientRectangle.Width - halfBorder) - x), height)
        End If
    End If

    MyBase.OnPaint(e)

End Sub

Enjoy!

Suggestions

The ColorBar can be modified to be drawn (or behave) just about any way one desires by defining your own OnPaint method and/or modifying the properties. Perhaps, inherit from the Windows.Forms base class control instead of UserControl and then draw your own border using the ControlPaint class. There are many possibilities.

Random Thoughts/Improvements

  • Recode using C# (to allow for property names that aren't keywords).
  • Add a Step property and PerformStep/Increment methods (some may find these handy).
  • The control properties can be set from the Windows Forms Designer, but the list of colors is not retained when entered by hand.
  • Grayscale option.
  • Use GDI or GDI+ gradients as opposed to the do-it-yourself kind. (The do-it-yourself method is more fun :).)
  • Marquee style control.
  • Display percentage complete or current value.
  • Thread safety.

History

  • Initial creation - 04/26/2008.
  • Corrected spelling/formatting - 05/03/08.
  • Added brush buffering and other minor improvements - 05/24/08.
  • Removed Finalize method - 05/24/08.
  • Added vertical and circular orientations; reversible color list; variable thicknesses for circular type; other minor code improvements - 06/14/08.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)