闪烁的自定义 ProgressBar

时间:2021-03-07 19:50:55

标签: c# winforms progress-bar onpaint

对于我正在制作的应用程序,我制作了一个基于 William Daniel 制作的自定义 ProgressBar:How to change the color of progressbar in C# .NET 3.5?

在使用较低的百分比值进行一些测试后,我注意到这种奇怪的闪烁:

The weird black lines shouldn't be there

我尝试将 DoubleBuffered 设置为 true,但它们仍然显示。

有谁知道为什么会出现这些奇怪的线条?

1 个答案:

答案 0 :(得分:2)

那不是轻弹,而是一种撕裂。自定义控件并不总是完全绘制;如果您有一个不允许 Form 正确重新绘制自身及其子控件的闭合循环,则可能会发生这种情况。
可能,使填充 ProgressBar 的过程异步。

一些建议的修改使其更流畅

  • 使用浮点值进行计算(不要转换为 int),并使用 RectagleF 来定义绘图的边界。

  • 移除位图并设置ControlStyles.OptimizedDoubleBuffer

    <块引用>

    如果为true,则控件首先绘制到缓冲区而不是直接绘制到屏幕上,这样可以减少闪烁。如果你设置这个 属性为 true,您还应该将 AllPaintingInWmPaint 设置为 true。

  • 然后当然设置ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint

    <块引用>

    AllPaintingInWmPaint:如果为真,控件将忽略窗口消息 WM_ERASEBKGND 以减少闪烁。 仅当 UserPaint 位设置为 true 时才应应用此样式。
    UserPaint:如果为 true,则控件绘制自身而不是绘制 操作系统这样做。如果为 false,则不会引发 Paint 事件。 此样式仅适用于从 Control 派生的类。

  • ControlStyles.Opaque 移除背景并让 ProgressBarRenderer 完成其工作,以填充 ProgressBar 的基本图形。

根据当前的Value集合计算ProgressBar的彩色部分的当前宽度:
float width = (this.Width - 3) * ((float)this.Value / this.Maximum)
如果 width > 0,则使用 Forecolor 和 BackColor 属性绘制 ProgressBar 颜色。当然,您可以使用一组不同的属性来定义这些颜色。

在绘图中添加一些抗锯齿,设置 Graphics.SmoothingMode,使 LinearGradientBrush 生成的颜色过渡更平滑。这在您设置 LinearGradientMode.Horizontal 时更有用。

结果:

Custom drawn ProgressBar


public class ProgressBarCustom : ProgressBar
{
    public ProgressBarCustom()
    {
        this.SetStyle(ControlStyles.OptimizedDoubleBuffer | 
            ControlStyles.AllPaintingInWmPaint | 
            ControlStyles.UserPaint | 
            ControlStyles.Opaque, true);
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        ProgressBarRenderer.DrawHorizontalBar(e.Graphics, this.ClientRectangle);

        float width = (this.Width - 3) * ((float)this.Value / this.Maximum);
        if (width > 0) {
            var rect = new RectangleF(1, 1, width, this.Height - 3);
            e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
            using (var brush = new LinearGradientBrush(rect, this.BackColor, this.ForeColor, LinearGradientMode.Horizontal)){
                e.Graphics.FillRectangle(brush, rect);
            }
        }
    }
}

作为一个小改进,您可以在 ProgressBar 的顶部绘制一条高 9 像素、颜色为半透明的线,以模拟原始反射
更改代码以添加Graphics.DrawLine()

// [...]
using (var brush = new LinearGradientBrush(rect, this.BackColor, this.ForeColor, LinearGradientMode.Horizontal))
using (var pen = new Pen(Color.FromArgb(40, 240,240,240), 9)) {
    e.Graphics.FillRectangle(brush, rect);
    e.Graphics.DrawLine(pen, 1.0f, 1.0f, width, 1.0f);
}

Custom drawn ProgressBar + reflaction

相关问题