我注意到.NET 2.0中的沼泽标准ProgressBar(Winforms)确实显示为Vista中花哨的动画发光条;但是,使用ProgressBarRenderer(通常在尝试在所有者绘制的列表视图,网格视图或其他此类控件中绘制进度条时)只提供没有漂亮动画的视觉样式。
我认为期待这只会神奇地工作是愚蠢的 - 我想Vista中的原生控件必须有某种嵌入式计时器或线程,在绘制静态图像时显然不存在。我确实看到如果你连续几次重绘一个ProgressBar控件(使用DrawToBitmap),你可以实际看到动画发光的不同阶段,所以我尝试使用计时器来自动重绘,但有些东西不太正确看起来,它也比实际的ProgressBar耗费了更多的CPU时间。
这似乎让我有两个不合标准的选择: a)使用ProgressBarRenderer并最终获得Vista“外观”,但没有动画;要么 b)使用计时器不断地将几个ProgressBars重绘为位图,并浪费CPU周期以使其看起来更好但仍然不完美。
我想知道是否有人有过在所有者绘制的控件中嵌入进度条的经验,并且可能知道比上面两个选项更好的方法 - 可以准确地再现发光/闪烁而不依赖于定时器和/或锤击CPU。
答案 0 :(得分:5)
我不得不拉一些非常疯狂的特技来完成这项工作。不幸的是,MSFT没有更新VisualStyleElement.ProgressBar类来添加Vista添加的部分。构造函数是私有的。我不得不猜测产生动画的部分。我对这段代码非常接近,它应该给你一些实验的东西:
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;
using System.Reflection;
namespace WindowsFormsApplication1 {
public partial class Form1 : Form {
VisualStyleElement pulseOverlay;
VisualStyleElement moveOverlay;
VisualStyleRenderer pulseRenderer;
VisualStyleRenderer moveRenderer;
Timer animator = new Timer();
public Form1() {
InitializeComponent();
ConstructorInfo ci = typeof(VisualStyleElement).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance,
null, new Type[] { typeof(string), typeof(int), typeof(int) }, null);
pulseOverlay = (VisualStyleElement)ci.Invoke(new object[] { "PROGRESS", 7, 0 });
moveOverlay = (VisualStyleElement)ci.Invoke(new object[] { "PROGRESS", 8, 0 });
pulseRenderer = new VisualStyleRenderer(pulseOverlay);
moveRenderer = new VisualStyleRenderer(moveOverlay);
animator.Interval = 20;
animator.Tick += new EventHandler(animator_Tick);
animator.Enabled = true;
this.DoubleBuffered = true;
}
void animator_Tick(object sender, EventArgs e) {
Invalidate();
}
int xpos;
protected override void OnPaint(PaintEventArgs e) {
Rectangle rc = new Rectangle(10, 10, 100, 20);
ProgressBarRenderer.DrawHorizontalBar(e.Graphics, rc);
rc = new Rectangle(10, 10, 50, 20);
ProgressBarRenderer.DrawHorizontalChunks(e.Graphics, rc);
xpos += 3;
if (xpos >= 30) xpos = -150; // Note: intentionally too far left
rc = new Rectangle(xpos, 10, 50, 20);
pulseRenderer.DrawBackground(e.Graphics, rc);
moveRenderer.DrawBackground(e.Graphics, rc);
}
}
}