防止自定义进度条闪烁

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

对于我正在制作的应用程序,我根据 William Daniel 制作的进度条制作了一个自定义进度条:How to Change the color of Progressbar in C# .NET 3.5?

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

我尝试将

DoubleBuffered
设置为 true,但它们仍然出现。

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

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

这不是“闪烁”,这是一种“撕裂”。自定义控件并不总是完全绘制;如果您有一个闭环不允许表单正确地重新绘制自身及其子控件,则可能会发生这种情况。 可能的话,使填充 ProgressBar 的过程异步。 一些建议的修改使其更流畅

使用浮点值进行计算(不要转换为

int
    ),并使用 RectagleF 定义绘图的边界。
  • 删除位图并设置

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

    设置为 true。

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

    AllPaintingInWmPaint

    :如果为 true,则控件会忽略窗口消息
    WM_ERASEBKGND

    以减少闪烁。 仅当 UserPaint 位设置为 true 时才应应用此样式。

    UserPaint
    :如果为真,则控件绘制自身而不是绘制控件
    操作系统这样做。如果为 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 时,这会更有用。 结果:

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

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

Graphics.DrawLine()
// [...] using (var brush = new LinearGradientBrush(rect, BackColor, 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); }

© www.soinside.com 2019 - 2024. All rights reserved.