闪烁的自定义 ProgressBar
Flickering custom ProgressBar
对于我正在制作的应用程序,我根据 William Daniel 制作的自定义 ProgressBar:How to change the color of progressbar in C# .NET 3.5?
在用较低的百分比值进行一些测试后,我注意到这个奇怪的闪烁:
我尝试将 DoubleBuffered
设置为 true 但它们仍然出现。
有谁知道为什么会出现这些奇怪的线条?
那不是闪烁,那是撕裂的一种形式。自定义控件并不总是完全绘制;如果您有一个不允许窗体正确重绘自身及其子控件的闭环,就会发生这种情况。
可能,使填充 ProgressBar 的过程异步。
对的一些修改建议使其更流畅:
使用浮点值进行计算(不要转换为 int
),并使用 RectagleF 定义绘图的边界。
删除位图并设置 ControlStyles.OptimizedDoubleBuffer:
If true, the control is first drawn to a buffer rather than directly to the screen, which can reduce flicker. If you set this
property to true, you should also set the AllPaintingInWmPaint
to true.
那么当然是设置ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint
:
AllPaintingInWmPaint
: If true, the control ignores the window message WM_ERASEBKGND
to reduce flicker.
This style should only be applied if the UserPaint bit is set to true.
UserPaint
: If true, the control paints itself rather than the
operating system doing so. If false, the Paint event is not raised.
This style only applies to classes derived from Control.
ControlStyles.Opaque
删除背景并让 ProgressBarRenderer 完成其工作,以填充 ProgressBar 的基本图形。
根据当前Value
设置计算ProgressBar彩色部分的当前宽度:
float width = (this.Width - 3) * ((float)this.Value / this.Maximum)
如果 width > 0
,则使用 Forecolor 和 BackColor 属性绘制 ProgressBar 颜色。当然,您可以使用一组不同的属性来定义这些颜色。
为绘图添加一些抗锯齿,设置 Graphics.SmoothingMode, to make the color transition generated by the LinearGradientBrush smoother. This is more useful when you set 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);
}
}
}
}
作为一个小改进,您可以在 ProgressBar 的顶部绘制一条 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);
}
对于我正在制作的应用程序,我根据 William Daniel 制作的自定义 ProgressBar:How to change the color of progressbar in C# .NET 3.5?
在用较低的百分比值进行一些测试后,我注意到这个奇怪的闪烁:
我尝试将 DoubleBuffered
设置为 true 但它们仍然出现。
有谁知道为什么会出现这些奇怪的线条?
那不是闪烁,那是撕裂的一种形式。自定义控件并不总是完全绘制;如果您有一个不允许窗体正确重绘自身及其子控件的闭环,就会发生这种情况。
可能,使填充 ProgressBar 的过程异步。
对的一些修改建议使其更流畅:
使用浮点值进行计算(不要转换为
int
),并使用 RectagleF 定义绘图的边界。删除位图并设置 ControlStyles.OptimizedDoubleBuffer:
If true, the control is first drawn to a buffer rather than directly to the screen, which can reduce flicker. If you set this property to true, you should also set the
AllPaintingInWmPaint
to true.那么当然是设置
ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint
:AllPaintingInWmPaint
: If true, the control ignores the window messageWM_ERASEBKGND
to reduce flicker. This style should only be applied if the UserPaint bit is set to true.
UserPaint
: If true, the control paints itself rather than the operating system doing so. If false, the Paint event is not raised. This style only applies to classes derived from Control.ControlStyles.Opaque
删除背景并让 ProgressBarRenderer 完成其工作,以填充 ProgressBar 的基本图形。
根据当前Value
设置计算ProgressBar彩色部分的当前宽度:
float width = (this.Width - 3) * ((float)this.Value / this.Maximum)
如果 width > 0
,则使用 Forecolor 和 BackColor 属性绘制 ProgressBar 颜色。当然,您可以使用一组不同的属性来定义这些颜色。
为绘图添加一些抗锯齿,设置 Graphics.SmoothingMode, to make the color transition generated by the LinearGradientBrush smoother. This is more useful when you set 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);
}
}
}
}
作为一个小改进,您可以在 ProgressBar 的顶部绘制一条 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);
}