Click here to Skip to main content
Click here to Skip to main content

BusyBar

, 25 May 2005
Rate this:
Please Sign up or sign in to vote.
The only progress bar you will ever need
Sample Image - BusyBar_2.png

Introduction

There are a lot of articles about progress bars (about a dozen in CodeProject [^] ) and they all have different properties. My aim in writing BusyBar was to make all the different styles available in one control. I have coded about twenty-five styles, but the real beauty of BusyBar is that it is easily extendable. I hope that people will give me new styles as they write them, to include in this project.

Using the Code

First, you must add BusyBar to your project. I have packaged BusyBar as a single C# source file (BusyBar.cs) and its associated RESX file (BusyBar.resx). Visual Studio is a bit temperamental, so please follow these instructions in order:

  • Copy the two files to your project directory.
  • Add a reference to System.Design.dll to your project.
  • Add BusyBar.cs to your project; BusyBar.resx will be added automatically.
  • Open BusyBar.cs in the designer; I have no idea why this is necessary.
  • Compile your project.
  • Add your assembly to your toolbox.

Here are detailed instructions for the "Add your assembly to your toolbox" step (it's not that obvious):

  • Display your toolbox.
  • Select the "My User Controls" tab on your toolbox.
  • Right-click and select "Add/Remove Items..."
  • The "Customize Toolbox" dialog appears.
  • Click "Browse..."
  • Browse to the (project)/bin/Release folder and select your *.exe.
  • Click "OK."

I have also now packaged it in a control library, as requested for VB.NET developers. You should now have the BusyBar control and some Painter components in your toolbox. Note that, they will only be enabled when you have a form open in design view. You are now ready to add a BusyBar control to your form. First, a quick diagram to help you to understand how BusyBar works:

The BusyBar class is a custom control, and handles the control stuff, like the CornerRadius, and the data properties, like the minimum, maximum and current values. It is also responsible for drawing the border, but it delegates the rest of the painting to an instance of IPainter. I have written some implementations of IPainter, each of which has various Preset settings.

You are now ready to add an instance of BusyBar to your form. This will draw the border, but you need to select an IPainter to draw the client area. You can do this in one of three ways:

  1. Add an instance of one of the Painters to your form ( they all derive from Component ), and set the PainterObject property of your BusyBar to point to your Painter. This is probably the easiest way. You can then set the properties of your Painter from within the form designer. Note that all the Painters have a Preset property. This is not persisted, but setting it will set the properties of your BusyBar and Painter to some predefined values.
  2. Set the value of the PainterPreset property of your BusyBar to one of the enumeration values. At runtime, the BusyBar will create an instance of the corresponding Painter. You can access this object through the PainterWorker property of your BusyBar, and set its properties in the code behind your form.
  3. Do it all in code. You can set either the PainterObject or PainterPreset properties of your BusyBar in code, and then set the Painter's properties through the PainterWorker property as above. This is the way to use a custom Painter if you write your own.

And that's it. Smile | :) You can use the demo to test various settings, and to see the different styles available so far.

Adding Design-time Bitmaps

You will notice that the BusyBar control and the Painter components have default bitmaps in your toolbox. If you want pretty bitmaps, you have to follow a few more steps:

  • Add the bitmaps to your project. Create a new folder called "Bitmaps" in your project and copy the bitmap files into it.
  • Set the Build action. Select the bitmap files in Solution Explorer and change the "Build Action" property to "Embedded Resource."
  • Set your default namespace. There is a class called ResFinder defined at the top of the BusyBar.cs file. Change the value of the DefaultNamespace constant to your default namespace. See "Points Of Interest" for an explanation.
  • Build your project. You may have to Rebuild your Solution.
  • Delete the old Toolbox items from your toolbox.
  • Add your assembly to your toolbox again.

You should now have shiny new bitmaps showing in your Toolbox Smile | :)

The Painters

This section will help you to choose a Painter, and explain the properties specific to each. I haven't included images of the different presets as there are too many. You can run the demo to see examples of what is possible.

PainterLine

This was the first painter I wrote, just to test the BusyBar control. So it's quite simple, but may be of some use. It only has one preset, "Bar," which sets the width of the line to 50, so it appears as a block of colour.

PainterXP

This is an attempt to replicate the .NET ProgressBar control. This Painter introduces the concept of "Blocks." When the BlockLineWidth property is greater than 0, a series of lines are drawn over the bar. When the BlockLineColor property is set to the BackgroundColor of the control, this splits the bar up into blocks.

It has two presets: "System," which sets the Bar.Pin property to BusyBar.Pins.Start, which anchors the bar on the left or top sides; and "Startup," which is a copy of the bar XP shows at startup.

PainterPathGradient

This is one of the most useful and configurable Painters. It uses a PathGradientBrush to paint the bar, which means you can set the colour gradient in two dimensions. Set the Shape property to one of the enumeration values to specify the base shape, and then set the Color properties to define the brush.

It has five presets: "Kitt," "Circle," "Startup," "Startup2003" and "Noise." These show the large range of effects that this Painter can produce. You get points if you know where the "Kitt" preset comes from Smile | :)

PainterClock

This Painter works best for a larger, square or slightly rectangular BusyBar control. It draws 12 marks round the edges, and two "hands" that rotate. It has two presets: "Watch" and "Circle." Note that the "Watch" preset is in CP colours!

PainterSillyscope

This Painter is supposed to imitate an oscilloscope. The line is drawn as a GraphicsPath. This is defined by the Shape and Points properties. If the Shape property is set to Line, then path.AddLines( points ) is called to create the path. This just results in straight lines connecting the points.

If the Shape property is set to Curve, then path.AddCurve( points, 1, points.Length - 3, tension / 100f ) is called to create the path. This results in curves connecting the middle points. The two end points are not drawn, they are just there to define the curvature at the start and end of the path. So this Shape requires at least four points.

If the Shape property is set to Bezier, then path.AddBeziers( points ) is called to create the path. This results in curves connecting the points. This Shape requires one point for the start position, and then three more points to describe each segment. So it must have 4, 7, 10, ... (1 + 3n) ... points.

Note that the "size" of the path described by the points array does not matter. The path is scaled according to the HorizontalScale and VerticalScale properties, which are percentages of the BusyBar control client area. Also, if the control is in Vertical mode, the path is rotated 90 degrees clockwise, so the points array must always be set horizontally.

There are a few presets in this Painter. "Triangle", "Square" and "Saw" are based on the Line shape; "Sine" is based on the Curve shape; and "Bezier" is based on the Bezier shape. The other two presets, "Circle" and "Heartbeat" are just for fun Smile | :)

PainterInstall

This Painter is a copy of the progress bar shown during an OS installation. I wrote it from memory; I think it's about right. It has two presets: "Install," which is the classic install bar, and "LED," which imitates a row of (blue) LEDs.

PainterFrustratoBar

This is a joke (I hope). It displays a bar that looks like the one in IE. It displays the log of the value, so it seems to go fast at first, and then slows down. Then it resets itself when it reaches a specified percentage, so it never gets to 100%. This was requested (honest)!

Writing Your Own Painter

All Painters must implement the IPainter interface :

    public interface IPainter : ICloneable
    {
        IPainter CreateCopy();
        BusyBar BusyBar { get; set; }
        void Reset();
        void Paint( Graphics g, Region r );
    }

You probably want to inherit from one of the existing classes. The derivation structure looks like this :

    IPainter
        PainterBase
            PainterLine
            PainterBlockBase
                PainterXP
                    PainterFrustratoBar
                PainterPathGradient
            PainterClock
            PainterSillyscope
            PainterInstall

If you derive from PainterBase, you just have to override the CreateCopy and Paint methods. PainterBase holds a reference to the BusyBar control, which it makes available through the protected Bar property. It also handles the ICloneable interface.

The Paint method is the most interesting. It is called from the OnPaint method of the BusyBar control, after it has drawn the border. The Graphics parameter enables you to do your drawing, and the Region parameter defines the client area available to you. The clip region of the Graphics object is already set to this Region.

The best way to understand this design is to have a look at the existing concrete Painter implementations.

Note: To test your Painter in the demo, alter the Painter property of Form1 to return an instance of your Painter (it's at the end of Form1.cs ). You will then be able to play with the settings from the PropertyGrids.

Have fun Smile | :)

Points of Interest

Getting the design-time bitmaps to work was a real pain. When Visual Studio embeds a resource, it pretends the default namespace to the name, and this is not configurable ( someone thought this was a good idea! ). Because BusyBar.cs is designed to be included in any project, the default namespace cannot be known. So I added a class called ResFinder in the default namespace, but you have to set the DefaultNamespace constant manually. I could not find a way around this :(

Bob Powell's website was a great help, in particular his article "How to find the elusive ToolboxBitmap icon" [^].

Conclusion

BusyBar provides a lot of functionality out of the box, but I hope that people will write more extensions, and email them to me to be included in updates of this article. Appropriate credit will of course be given.

I have had fun writing this, especially the "Kitt" and "Heartbeat" presets were quite gratifying. I hope you like what I have done Smile | :)

History

  • 19th May 2005 : Version 1
  • 26th May 2005 : Version 2
    • Fixed the threading bug in the demo.
    • Removed SCC links as requested.
    • Packaged in a strong-named library assembly as requested.
    • Added preset "Startup" to PainterXP.
    • Added preset "Startup2003" to PainterPathGradient.
    • Added PainterInstall with two presets.
  • 27th May 2005 : Version 3
    • Fixed bug when Minimum was not zero.
    • Added PainterFrustratoBar as requested.

License

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

About the Author

Nicholas Butler

United Kingdom United Kingdom

I built my first computer, a Sinclair ZX80, on my 11th birthday in 1980.
In 1992, I completed my Computer Science degree and built my first PC.
I discovered C# and .NET 1.0 Beta 1 in late 2000 and loved them immediately.
I have been writing concurrent software professionally, using multi-processor machines, since 1995.
 
In real life, I have spent 3 years travelling abroad,
I have held a UK Private Pilots Licence for 20 years,
and I am a PADI Divemaster.
 
I now live near idyllic Bournemouth in England.
 
If you would like help with multithreading, please contact me via my website:
 
 
I can work 'virtually' anywhere!

Comments and Discussions

 
GeneralSystem.NullReferenceException occurred Pinmemberdchris_med10-May-07 20:48 
Generalshape PinmemberNRG568-Apr-07 7:43 
GeneralStatusStrip Pinmemberrykema21-Feb-07 6:19 
GeneralRe: StatusStrip Pinmemberrykema21-Feb-07 10:17 
GeneralBrilliant PinmemberChewsHumans6-Feb-07 15:06 
QuestionLicense? Pinmemberenovales9-Dec-05 8:05 
GeneralI can't use BusyBar PinmemberAfsoon30-Aug-05 3:03 
QuestionHow do you change properties programmatically? PinmemberBruceN31-May-05 12:56 
AnswerRe: How do you change properties programmatically? PinmemberNicholas Butler31-May-05 13:37 
GeneralRe: How do you change properties programmatically? PinmemberBruceN31-May-05 14:05 
General.NET CF PinsussotherJohn31-May-05 5:08 
Hey, does this work for the .NET compact Framework (PocketPC) or what can i do to get it to work, since the system.design.dll is not supported i think.
john
GeneralRe: .NET CF PinmemberNicholas Butler31-May-05 13:38 
GeneralVersion 3 now available PinmemberNicholas Butler26-May-05 22:07 
QuestionIs there automatic support for the Frustrato-Bar? PinsussAnonymous26-May-05 13:55 
AnswerRe: Is there automatic support for the Frustrato-Bar? PinmemberNicholas Butler26-May-05 22:05 
GeneralVersion 2 now available PinmemberNicholas Butler25-May-05 23:24 
GeneralGreat PinmemberDouglas Troy24-May-05 7:06 
GeneralRe: Great PinmemberNicholas Butler25-May-05 23:22 
GeneralCool Project -- one comment PinmemberPaul Brower23-May-05 3:06 
GeneralRe: Cool Project -- one comment PinmemberNicholas Butler25-May-05 23:21 
GeneralLooks Cool... Pinmemberjonnyvee21-May-05 11:11 
GeneralRe: Looks Cool... PinmemberNicholas Butler21-May-05 16:50 
Generaldoes not work with VS2005beta2 PinmemberMP3Observer20-May-05 0:32 
GeneralRe: does not work with VS2005beta2 PinmemberJonathan Merriweather20-May-05 19:26 
GeneralRe: does not work with VS2005beta2 PinmemberNicholas Butler20-May-05 22:15 
GeneralRe: does not work with VS2005beta2 Pinmembereyeofdstrm25-May-05 2:35 
GeneralRe: does not work with VS2005beta2 PinmemberNicholas Butler25-May-05 23:20 
GeneralRe: does not work with VS2005beta2 PinmemberNicholas Butler25-May-05 23:19 
GeneralGreat Job Pinmemberoykica19-May-05 16:05 
GeneralRe: Great Job PinmemberNicholas Butler20-May-05 22:07 
GeneralWell done! Pinmemberthomasswilliams19-May-05 14:16 
GeneralRe: Well done! PinmemberNicholas Butler20-May-05 22:06 
GeneralRe: Well done! PinmemberNicholas Butler25-May-05 23:17 
GeneralRe: Well done! Pinmembercomputerguru9238227-Mar-06 6:14 

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

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

| Advertise | Privacy | Mobile
Web03 | 2.8.140721.1 | Last Updated 26 May 2005
Article Copyright 2005 by Nicholas Butler
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid