Click here to Skip to main content
6,822,613 members and growing! (20,605 online)
Email Password   helpLost your password?
Desktop Development » Progress Controls » General     Intermediate License: The Code Project Open License (CPOL)

Circular Progress Indicator

By Nitoc3

Firefox like circular progress indicator
C#, .NET
Posted:2 Nov 2008
Views:38,018
Bookmarked:92 times
printPrint   add Share
      Discuss Discuss   Broken Article?Report  
36 votes for this article.
Popularity: 7.30 Rating: 4.69 out of 5

1

2
2 votes, 5.6%
3
9 votes, 25.0%
4
25 votes, 69.4%
5

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
  • AutoStart - Sets if the animation should start automatically
  • AnimationSpeed - Sets the animation speed 

To start the animation, just call Start():

progressIndicator.Start(); 

And to stop it, just call Stop():

progresIndicator.Stop();

The Control Code

namespace ProgressControls
{
    /// <summary>
    /// Firefox like circular progress indicator.
    /// </summary>
    public partial class ProgressIndicator : Control
    {
        #region Constructor
        /// <summary>
        /// Default constructor for the ProgressIndicator.
        /// </summary>
        public ProgressIndicator()
        {
            InitializeComponent();
            SetStyle(ControlStyles.OptimizedDoubleBuffer | 
			ControlStyles.AllPaintingInWmPaint, true);
            ResizeRedraw = true;

            if (AutoStart)
                timerAnimation.Start();
        }
        #endregion

        #region Private Fields
        private int _value = 1;
        private int _interval = 100;
        private Color _circleColor = Color.FromArgb(20, 20, 20);
        private bool _autoStart;
        private bool _stopped = true;
        private float _circleSize = 1.0F;
        #endregion

        #region Public Properties
        /// <summary>
        /// Gets or sets the base color for the circles.
        /// </summary>
        [DefaultValue(typeof(Color), "20, 20, 20")]
        [Description("Gets or sets the base color for the circles.")]
        [Category("Appearance")]
        public Color CircleColor
        {
            get { return _circleColor; }
            set
            {
                _circleColor = value;
                Invalidate();
            }
        }

        /// <summary>
        /// Gets or sets a value indicating if the animation should start automatically.
        /// </summary>
        [DefaultValue(false)]
        [Description("Gets or sets a value indicating if the animation 
		should start automatically.")]
        [Category("Behavior")]
        public bool AutoStart
        {
            get { return _autoStart; }
            set
            {
                _autoStart = value;

                if (_autoStart && !DesignMode)
                    Start();
                else
                    Stop();
            }
        }

        /// <summary>
        /// Gets or sets the scale for the circles raging from 0.1 to 1.0.
        /// </summary>
        [DefaultValue(1.0F)]
        [Description("Gets or sets the scale for the circles raging from 0.1 to 1.0.")]
        [Category("Appearance")]
        public float CircleSize
        {
            get { return _circleSize; }
            set
            {
                if (value <= 0.0F)
                    _circleSize = 0.1F;
                else
                    _circleSize = value > 1.0F ? 1.0F : value;

                Invalidate();
            }
        }

        /// <summary>
        /// Gets or sets the animation speed.
        /// </summary>
        [DefaultValue(75)]
        [Description("Gets or sets the animation speed.")]
        [Category("Behavior")]
        public int AnimationSpeed
        {
            get { return (-_interval + 400) / 4; }
            set
            {
                checked
                {
                    int interval = 400 - (value * 4);

                    if (interval < 10)
                        _interval = 10;
                    else
                        _interval = interval > 400 ? 400 : interval;

                    timerAnimation.Interval = _interval;
                }
            }
        }
        #endregion

        #region Public Methods
        /// <summary>
        /// Starts the animation.
        /// </summary>
        public void Start()
        {
            timerAnimation.Interval = _interval;
            _stopped = false;
            timerAnimation.Start();
        }

        /// <summary>
        /// Stops the animation.
        /// </summary>
        public void Stop()
        {
            timerAnimation.Stop();
            _value = 1;
            _stopped = true;
            Invalidate();
        }
        #endregion

        #region Overrides
        protected override void OnPaint(PaintEventArgs e)
        {
            const float angle = 360.0F / 8;

            GraphicsState oldState = e.Graphics.Save();

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

            for (int i = 1; i <= 8; i++)
            {
                int alpha = _stopped ? (int)(255.0F * (1.0F / 8.0F)) : 
				(int)(255.0F * (i / 8.0F));

                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);
                }
            }

            e.Graphics.Restore(oldState);
            base.OnPaint(e);
        }

        protected override void OnResize(EventArgs e)
        {
            SetNewSize();
            base.OnResize(e);
        }

        protected override void OnSizeChanged(EventArgs e)
        {
            SetNewSize();
            base.OnSizeChanged(e);
        }

        #endregion

        #region Private Methods

        private void SetNewSize()
        {
            int size = Math.Max(Width, Height);
            Size = new Size(size, size);
        }

        private void IncreaseValue()
        {
            if (_value + 1 <= 8)
                _value++;
            else
                _value = 1;
        }

        #endregion

        #region Timer

        private void timerAnimation_Tick(object sender, EventArgs e)
        {
            if (!DesignMode)
            {
                IncreaseValue();
                Invalidate();
            }
        }
        #endregion
    }
}

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. 

History

  • 2nd November, 2008: Initial post

License

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

About the Author

Nitoc3


Member

Occupation: Software Developer
Location: Portugal Portugal

Other popular Progress Controls articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 25 of 29 (Total in Forum: 29) (Refresh)FirstPrevNext
GeneralCan it be used on C# win mobile? Pinmemberaaronlzw_2116:39 14 Oct '09  
GeneralRe: Can it be used on C# win mobile? PinmemberNitoc34:48 15 Oct '09  
QuestionPercentage PinmemberOKA13314:58 25 Aug '09  
AnswerRe: Percentage PinmemberNitoc34:58 26 Aug '09  
GeneralRe: Percentage PinmemberOKA13314:54 26 Aug '09  
GeneralFading Colors Pinmemberkjward7:21 20 Jul '09  
GeneralRe: Fading Colors PinmemberNitoc34:53 26 Aug '09  
GeneralHow to use this control?? PinmemberPayam Rastogi3:58 11 Feb '09  
GeneralRe: How to use this control?? PinmemberNitoc34:44 11 Feb '09  
GeneralRe: How to use this control?? PinmemberPayam Rastogi4:54 11 Feb '09  
GeneralRe: How to use this control?? PinmemberNitoc35:23 11 Feb '09  
GeneralUsefull control PinmemberLuc Bardez5:44 18 Dec '08  
GeneralRe: Usefull control PinmemberNitoc314:56 18 Dec '08  
GeneralThis control in WPF? PinmemberYogesh Jagota7:36 9 Nov '08  
GeneralRe: This control in WPF? PinmemberYogesh Jagota8:00 9 Nov '08  
GeneralBy the way PinmemberD Strauss20:57 3 Nov '08  
GeneralAwesome!!! PinmemberD Strauss20:54 3 Nov '08  
GeneralRe: Awesome!!! PinmemberNitoc33:02 4 Nov '08  
GeneralRe: Awesome!!! PinmemberYeorwned11:42 18 Sep '09  
GeneralDeja Vu PinmemberDmitri Nesteruk21:14 2 Nov '08  
GeneralRe: Deja Vu PinmemberNitoc35:15 3 Nov '08  
GeneralRe: Deja Vu PinmemberDmitri Nesteruk8:55 3 Nov '08  
GeneralRe: Deja Vu PinmemberVCKicks8:55 3 Nov '08  
GeneralRe: Deja Vu PinmemberNitoc311:13 3 Nov '08  
GeneralRe: Deja Vu PinmemberSneaki20:14 3 Nov '08  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

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

PermaLink | Privacy | Terms of Use
Last Updated: 2 Nov 2008
Editor: Deeksha Shenoy
Copyright 2008 by Nitoc3
Everything else Copyright © CodeProject, 1999-2010
Web09 | Advertise on the Code Project