如何在ProgressBar的中间显示进度百分比?

问题描述 投票:0回答:1

我尝试使用标签,这是代码:

public partial class Form1 : Form
{
    private readonly HttpClient _httpClient;
    private readonly ProgressBar _progressBar;
    private readonly Label _labelProgress;
    private readonly Timer downloadTimer;
    private readonly Radar radar;

    public Form1()
    {
        InitializeComponent();

        _httpClient = new HttpClient();

        _progressBar = new ProgressBar
        {
            Size = lblNextTimeDownload.Size,
            Minimum = 0,
            Maximum = 100,
            Value = 0,
        };

        _labelProgress = new Label
        {
            AutoSize = false,
            TextAlign = ContentAlignment.MiddleCenter,
            Font = new Font("Arial", 12, FontStyle.Regular),
        };

        _progressBar.Controls.Add(_labelProgress);
        Controls.Add(_progressBar);
    }
}

结果是

_labelProgress
位于进度条的左上角

如果在标签的实例中我添加以下行:

Dock = DockStyle.Fill,

像这样:

_labelProgress = new Label
{
    AutoSize = false,
    TextAlign = ContentAlignment.MiddleCenter,
    Dock = DockStyle.Fill,
    Font = new Font("Arial", 12, FontStyle.Regular),
};

然后Label的文本定位在ProgresBar的中心中间,但它也与整个ProgressBar重叠。

c# winforms progress-bar
1个回答
2
投票

我的建议是避免为此使用标签。除此之外,当您的表单在 DpiAware 上下文中缩放时,您可能会发现它的缩放方式与 ProgressBar 不同。

您可以使用进度条的 DC 直接将百分比绘制到控件的表面上。为此重写 WndProc 并处理

WM_PAINT

当然,您需要构建一个自定义控件,覆盖它的 WndProc,捕获

WM_PAINT
,然后使用 GetWindowDc() 获取其设备上下文。
然后调用
Graphics.FromHdcInternal()
生成 Graphics 对象,然后将其传递给
TextRenderer.DrawText()
以将百分比呈现为文本。

ReleaseDC() 必须在之后调用,以释放 HDC。

using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Windows.Forms;

[ToolboxItem(true), DesignerCategory("code")]
public class ProgressBarEx : ProgressBar {
    Color percentageColor = Color.Black;
    int percentageDecimals = 0;
    public ProgressBarEx() { }

    [DefaultValue(typeof(Color), "Black")]
    public Color PercentageColor { 
        get => percentageColor; 
        set { 
            if (percentageColor != value) {
                percentageColor = value;
                Invalidate();
            }
        } 
    }

    [DefaultValue(0), Description("Number of decimals (0-4)")]
    public int PercentageDecimals {
        get => percentageDecimals;
        set { 
            if (percentageDecimals != value) {
                percentageDecimals = Math.Max(Math.Min(value, 4), 0);
                Invalidate();
            }
        }
    }

    protected override void WndProc(ref Message m) {
        base.WndProc(ref m);
        switch (m.Msg) {
            case WM_PAINT:
                if (!IsHandleCreated) return;
                float percentage = (float)Value / Maximum;
                percentage = float.IsNaN(percentage) ? 0 : percentage;
                var hDC = GetWindowDC(this.Handle);
                try {
                    using (var g = Graphics.FromHdcInternal(hDC)) {
                        TextRenderer.DrawText(g, percentage.ToString($"P{percentageDecimals}"), 
                            Font, ClientRectangle, percentageColor);
                    }
                }
                finally {
                    if (hDC != IntPtr.Zero) ReleaseDC(this.Handle, hDC);
                }
                m.Result = IntPtr.Zero;
                break;
            default:
                break;
        }
    }

    const int WM_PAINT = 0x000F;

    [DllImport("user32.dll")]
    static extern IntPtr GetWindowDC(IntPtr hWnd);

    [DllImport("user32.dll")]
    static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDc);
}
© www.soinside.com 2019 - 2024. All rights reserved.