Click here to Skip to main content
15,867,568 members
Articles / Programming Languages / C#

Circular Progress Indicator

Rate me:
Please Sign up or sign in to vote.
4.84/5 (85 votes)
1 Jul 2010CPOL5 min read 315.2K   16.2K   228   79
Firefox like circular progress indicator
Image 1

Introduction

I've always liked the little circular progress indicator on Firefox top right corner when loading a page but I couldn't find any like it to use with my projects, so I've made one myself.

Using the Code

Using the control is very simple, there are only four properties and two methods that you need to be aware of:

  • CircleColor - Changes the base color of the circles
  • CircleSize - Changes the diameter of the circles, this value is relative and proportional to the control size and ranges between 0.1 and 1.0
  • AutoStart - Sets if the animation should start automatically
  • AnimationSpeed - Sets the animation speed 
  • NumberOfCircles - Sets the maximum number of circles that can be drawn in the control, this value must be greater than 0
  • NumberOfVisibleCircles - Sets the number of circles that are visible in the control, must always be less or equal than the NumberOfCircles
  • Percentage - Sets a percentage value that can be shown in the center of the control, this value must be between 0 and 100
  • ShowPercentage - Sets a value that allows to show or hide the percentage value
  • ShowText - Sets a value that allows to show the control text
  • TextDisplay - This property is just a helper property, it allows to enable or disable both text and percentage with one property
  • Rotation - Sets the direction in which the control will rotate

To start the animation, just call Start():

C#
progressIndicator.Start(); 

And to stop it, just call Stop():

C#
progresIndicator.Stop();

The Control Code

Drawing the Circles

The circles are drawn around a circumference with the diameter of the control. Since the number of circles is variable, we need to calculate the rotation angle for each circle. The minimum number of circles must be 1 with no upper limit control. Drawing the circles is done using a call to RotateTransform that rotates the drawing position to the angle passed as a parameter. Drawing the circles in sequence, decreasing the amount of alpha in the circle color gives the fading effect of the control. To animate, the control is redrawn at time intervals always changing the position of the darker circle by one place forward, giving the illusion of motion. The control can be rotated clockwise or counter-clockwise and direction of rotation is achieved by multiplying the angle by 1 or -1. Checking the code, this line is found:

C#
e.Graphics.RotateTransform(angle * _value * (int)_rotation);

This piece of code sets the start position of each rotation phase multiplying the section angle by a value that is incremented by an internal timer. The maximum number of circles shown at a given time is defined by the NumberOfVisibleCircles property. This property determines the effective number of circles that are drawn in the control, this is different from the NumberOfCircles property. This last property sets the number of circles that can be drawn, is like reserving spaces for the circles even if we don't use them all. This gives the effect of tightening the circles together when the number of visible circles decreases and the opposite effect when it increases.

C#
float angle = 360.0F / _numberOfCircles;

GraphicsState oldState = e.Graphics.Save();

e.Graphics.TranslateTransform(Width / 2.0F, Height / 2.0F);
e.Graphics.RotateTransform(angle * _value * (int)_rotation);
e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;

for (int i = 1; i <= _numberOfCircles; i++)
{
    int alphaValue = (255.0F * (i / (float)_numberOfVisibleCircles)) > 255.0 ? 0 : 
	(int)(255.0F * (i / (float)_numberOfVisibleCircles));
    int alpha = _stopped ? (int)(255.0F * (1.0F / 8.0F)) : alphaValue;

    Color drawColor = Color.FromArgb(alpha, _circleColor);

    using (SolidBrush brush = new SolidBrush(drawColor))
    {
        float sizeRate = 4.5F / _circleSize;
        float size = Width / sizeRate;

        float diff = (Width / 4.5F) - size;

        float x = (Width / 9.0F) + diff;
        float y = (Height / 9.0F) + diff;
        e.Graphics.FillEllipse(brush, x, y, size, size);
        e.Graphics.RotateTransform(angle * (int)_rotation);
    }
}

e.Graphics.Restore(oldState);

Drawing the Percentage and the Text

The percentage is an optional feature, since the primary purpose isn't to show a progress value but that something is going on. The percentage text isn't shown by default and wasn't even part of the original idea. Anyway I have been reading some comments from people requesting new features and giving some nice ideas that I've decided to update the control and implement some new features. One of them was this one. The percentage is set through the Percentage property and can be enabled and disabled from the ShowPercentage property. The Text property follows the same reasoning. It wasn't part of the original plan, but as SohjSolwin suggested, it can be useful in some cases, we never know when or where this control will be used. So, from this version on, the control has the ability of drawing both of them like shown below:

C#
string percent = GetDrawText();

if (!string.IsNullOrEmpty(percent))
{
    SizeF textSize = e.Graphics.MeasureString(percent, Font);
    float textX = (Width / 2.0F) - (textSize.Width / 2.0F);
    float textY = (Height / 2.0F) - (textSize.Height / 2.0F);
    StringFormat format = new StringFormat
    {
        Alignment = StringAlignment.Center,
        LineAlignment = StringAlignment.Center
    };

    RectangleF rectangle = new RectangleF(textX, textY, textSize.Width, textSize.Height);
        

    using (SolidBrush textBrush = new SolidBrush(ForeColor))
    {
        e.Graphics.DrawString(percent, Font, textBrush, rectangle, format);
    } 
}

Why both Percentage and the Text?

When the control is being used to show progress, it is possible to show a message about what is going on and at the same time the progress percentage. Both of them are independent and have different purposes. Even if they are drawn at the same time internally, if I just need to change the value of the percentage, it's easier to do this:

C#
progressIndicator.Percentage = 50.25F;

And let the control add the "%" sign and do the rest of the formatting. It's much more intuitive and simple than this:

C#
progressIndicator.Text = string.Format("{0:0:##} %}, 50.25F);

On the other hand, the percentage property doesn't allow text, so it's needs another field to set the text to draw. The final string that is displayed is built using the Text and the Percentage property in the method displayed below, the method checks the values of the _showText and _showPercentage fields and constructs a string based on their values, returning an empty string if both fields are set to false.

C#
private string GetDrawText()
{
    string percent = string.Format(CultureInfo.CurrentCulture, "{0:0.##} %", _percentage);

    if (_showText && _showPercentage)
        return string.Format("{0}{1}{2}", percent, Environment.NewLine, Text);

    if (_showText)
        return Text;

    if (_showPercentage)
        return percent;

    return string.Empty;
}

The rest of the control code is short and simple to understand, so I've decided to remove it from the article leaving only the pieces that matter. If you have any questions, please leave a comment.

Points of Interest

There's nothing more to it. It is particularly useful in situations where the progress bar hasn't made any progress for a long time and we want to pass the message that something is being done. Mainly, it has been fun to program. :)

Credits

I would like to thank SohjSolwin for his contribution with the rotation and number of visible circles part of the code that I've included in this release with minor modifications, and also for the text drawing suggestion instead of only showing the percentage.

History

  • 2nd November, 2008: Initial post
  • 26th June, 2010: Update to version 1.1, new features are:
    • Variable number of circles (version 1 has a fixed number of 8)
    • It is possible to draw a percentage value
  • 1st July, 2010: Update to version 1.2, new features are:
    • Rotation can be clockwise or counter-clockwise
    • It is possible to draw a text string in addition to the percentage value
    • Variable number of visible circles (version 1.1 has a fixed number of 8)

License

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


Written By
Software Developer
Portugal Portugal
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionIts awesome. Thanks. Pin
pkkalra197826-Sep-11 21:16
pkkalra197826-Sep-11 21:16 
GeneralLike !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Pin
raananv31-Aug-11 12:48
raananv31-Aug-11 12:48 
GeneralMy vote of 5 Pin
TheF®eeSurfer6-Apr-11 0:34
TheF®eeSurfer6-Apr-11 0:34 
GeneralAnother new vote Pin
apiegoku22-Sep-10 11:08
apiegoku22-Sep-10 11:08 
GeneralMy vote of 5 Pin
Vladimir Svyatski21-Sep-10 11:00
professionalVladimir Svyatski21-Sep-10 11:00 
GeneralVery usefull progress indicator Pin
redhatee200611-Aug-10 5:44
redhatee200611-Aug-10 5:44 
GeneralRe: Very usefull progress indicator Pin
Nitoc317-Aug-10 7:11
Nitoc317-Aug-10 7:11 
GeneralMy vote of 5 Pin
kobymeir17-Jul-10 4:40
kobymeir17-Jul-10 4:40 
GeneralMy vote of 5 Pin
Huseyin OZCAKIR9-Jul-10 23:14
Huseyin OZCAKIR9-Jul-10 23:14 
GeneralMy vote of 5 Pin
garycoggins8-Jul-10 4:12
garycoggins8-Jul-10 4:12 
Generaluse of control Pin
Member 347198330-Jun-10 8:48
Member 347198330-Jun-10 8:48 
GeneralRe: use of control Pin
SohjSolwin1-Jul-10 11:12
SohjSolwin1-Jul-10 11:12 
GeneralA few updates and request for permission Pin
SohjSolwin29-Jun-10 11:17
SohjSolwin29-Jun-10 11:17 
GeneralRe: A few updates and request for permission Pin
Nitoc330-Jun-10 1:13
Nitoc330-Jun-10 1:13 
GeneralRe: A few updates and request for permission Pin
SohjSolwin30-Jun-10 7:52
SohjSolwin30-Jun-10 7:52 
GeneralRe: A few updates and request for permission Pin
Nitoc330-Jun-10 8:28
Nitoc330-Jun-10 8:28 
GeneralRe: A few updates and request for permission Pin
SohjSolwin2-Jul-10 3:27
SohjSolwin2-Jul-10 3:27 
GeneralRe: A few updates and request for permission [modified] Pin
Nitoc32-Jul-10 4:10
Nitoc32-Jul-10 4:10 
Generalfun Pin
Member 14901625-Jun-10 20:32
Member 14901625-Jun-10 20:32 
GeneralRe: fun Pin
Nitoc326-Jun-10 7:39
Nitoc326-Jun-10 7:39 
QuestionCan it be used on C# win mobile? Pin
aaronlzw_2114-Oct-09 15:39
aaronlzw_2114-Oct-09 15:39 
AnswerRe: Can it be used on C# win mobile? Pin
Nitoc315-Oct-09 3:48
Nitoc315-Oct-09 3:48 
QuestionRe: Can it be used on C# win mobile? Pin
stijn.vandenbroucke9-Oct-11 2:25
stijn.vandenbroucke9-Oct-11 2:25 
QuestionPercentage Pin
OKA13325-Aug-09 13:58
OKA13325-Aug-09 13:58 
AnswerRe: Percentage Pin
Nitoc326-Aug-09 3:58
Nitoc326-Aug-09 3:58 

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.