Home > Software design >  Visual Studio Half Circle Progress Bars
Visual Studio Half Circle Progress Bars

Time:12-04

I would like to achieve semi-circle progress bars but I don't have enough experience in visual studio, I did find a circular progress bar Nuget pack that is possible to do full circle but I couldn't find a way to succeed in making half one (even tried to modify source code of CircularProgressBar Nuget pack), is there anyone can give tip or way of achieving that. Thanks.

enter image description here

CodePudding user response:

SO70211529

You can subclass and create a custom semicircle progress control. All what you need to do is a 180°-based calculation and drawing rather than a 360°.

Derive a new class from the Label control and import:

using System;
using System.Drawing;
using System.Drawing.Design;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using System.ComponentModel;

And encapsulate:

  • The key properties of a progress control, Value, Minimum, and Maximum.
  • Properties used to draw the progress, track size, track and value colors.
  • custom event to notify a subscriber with the value changes.
  • The drawing routine which calls the Graphics.DrawArc method to draw both, the track and value arcs.
[DesignerCategory("Code")]
[DefaultProperty("Value")]
[DefaultEvent("ValueChanged")]
[ToolboxItem(typeof(ToolboxItem))]
[ToolboxBitmap(typeof(ProgressBar))]
public class SemiCircleProgress : Label
{
    #region ctor

    public SemiCircleProgress() : base() { }

    #endregion

    #region Properties

    private int _value;
    [DefaultValue(0)]            
    public int Value
    {
        get => _value;
        set
        {
            if (_value != value)
            {
                _value = value < Minimum ? Minimum : value > Maximum ? Maximum : value;
                Invalidate();
                OnValueChanged(new EventArgs());
            }
        }
    }

    private int _min;
    [DefaultValue(0)]         
    public int Minimum
    {
        get => _min;
        set
        {
            if (_min != value)
            {
                _min = Math.Max(value, 0);
                if (value > _value) _value = value;
                if (value > _max) _max = value;
                Invalidate();
            }
        }
    }

    private int _max = 100;            
    [DefaultValue(100)]
    public int Maximum
    {
        get => _max;
        set
        {
            if (_max != value)
            {
                if (value < 1) value = 1;
                if (value < _value) _value = value;
                _max = value;
                Invalidate();
            }
        }
    }

    private int _trackSize = 10;
    [DefaultValue(10)]
    public int TrackSize
    {
        get => _trackSize;
        set
        {
            if (_trackSize != value)
            {
                _trackSize = value;
                Invalidate();
            }
        }
    }

    private Color _trackColor = Color.Gray;
    [DefaultValue(typeof(Color), "Gray")]
    public Color TrackColor
    {
        get => _trackColor;
        set
        {
            if (_trackColor != value)
            {
                _trackColor = value;
                Invalidate();
            }
        }
    }

    private Color _valueColor = Color.FromArgb(255, 128, 0);
    [DefaultValue(typeof(Color), "255, 128, 0")]
    public Color ValueColor
    {
        get => _valueColor;
        set
        {
            if (_valueColor != value)
            {
                _valueColor = value;
                Invalidate();
            }
        }
    }

    private bool _showValue;
    [DefaultValue(false)]
    public bool ShowValue
    {
        get => _showValue;
        set
        {
            if (_showValue != value)
            {
                _showValue = value;
                Invalidate();
            }
        }
    }
        
    protected override Size DefaultSize => new Size(100, 100);

    #endregion

    #region Paint

    protected override void OnPaint(PaintEventArgs e)
    {            
        var g = e.Graphics;            
        var r = new Rectangle(_trackSize, _trackSize,
            Math.Max(_trackSize * 2, Width - _trackSize * 2),
            Math.Max(_trackSize * 2, (Height - _trackSize * 2) * 2));

        using (var pnTrack = new Pen(_trackColor, _trackSize))
        {
            g.Clear(BackColor);
            g.SmoothingMode = SmoothingMode.AntiAlias;
            g.PixelOffsetMode = PixelOffsetMode.Half;
            g.DrawArc(pnTrack, r, 180, 180);

            if (Value > Minimum)
            {
                var val = (int)Math.Round(180d / Maximum * Value);
                pnTrack.Color = _valueColor;
                // pnTrack.Width -= 2; // uncomment and try...
                g.DrawArc(pnTrack, r, 180, val);
            }
        }

        if (_showValue)
        {
            TextRenderer.DrawText(g, Value.ToString(), Font, r, ForeColor,
                TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter);
        }
    }

    #endregion

    #region Events

    public event EventHandler ValueChanged;

    protected virtual void OnValueChanged(EventArgs e) =>
        ValueChanged?.Invoke(this, e);

    #endregion
}

ToDo : Hide the not used properties of the base class:

[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override string Text { get => base.Text; set => base.Text = value; }

[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new Image Image { get; set; }

// ...etc.
  • Related