【问题标题】:Visual Studio Half Circle Progress BarsVisual Studio 半圆进度条
【发布时间】:2022-01-09 15:46:46
【问题描述】:

我想实现半圆形进度条,但我没有足够的视觉工作室经验,我确实找到了一个圆形进度条 Nuget 包,它可以做完整的圆形,但我找不到办法成功制作了一半(甚至尝试修改 CircularProgressBar Nuget 包的源代码),有没有人可以提供提示或实现方式。谢谢。

What circular progress bar Nuget pack offers

Half-circular progress bar that I am trying to implement on my design

【问题讨论】:

  • 考虑使用 nuget one 并在其下半部分使用不透明蒙版?
  • 它只会隐藏进度条的下部,它更像是一种解决方法而不是解决方案
  • 在 winform 应用中可以吗?
  • 是的,我试图隐藏它,但是当我做超过 1 个小节时,它会像在太空中一样失控,我也找不到像在 Photoshop 中那样将 2 个链接在一起的方法
  • 哦,你使用的是winforms?不是wpf?抱歉,我对 winforms 几乎没有经验...

标签: c# user-interface progress-bar visual-studio-2019 nuget-package


【解决方案1】:

您可以继承并创建自定义半圆进度控件。您需要做的只是基于 180° 的计算和绘图,而不是 360°。

Label 控件派生一个新类并导入:

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

并封装:

  • 进度控件的关键属性ValueMinimumMaximum
  • 用于绘制进度、轨道大小、轨道和值颜色的属性。
  • 自定义事件通知订阅者值发生变化。
  • 调用Graphics.DrawArc 方法来绘制轨道和值弧的绘图例程。
[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
}

待办事项:隐藏基类未使用的属性:

[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.

【讨论】:

  • 是的,它确实有效,感谢您教我更多关于视觉工作室的知识。现在我知道如何创建自定义控制器等了。
【解决方案2】:

这可能不是最好的解决方案,但您可以在圆形进度条项目的下半部分添加一个面板。然后将StartAngle 设置为180,将Maximum 设置为最大可达值的两倍。这里有一个例子的小片段(又快又脏):

【讨论】:

  • 是的,这一直是我现在的特殊解决方案,直到我找到最好的方法,谢谢你的提示
猜你喜欢
  • 1970-01-01
  • 2023-02-23
  • 1970-01-01
  • 2015-01-11
  • 1970-01-01
  • 1970-01-01
  • 2022-07-19
  • 2018-01-02
  • 1970-01-01
相关资源
最近更新 更多