我想开发一个标签,以淡入淡出的方式显示文字。我希望我需要处理这个绘画,以便在每次迭代时向右添加几个像素。但是,我遇到了障碍,无法使任何动画工作。这是我到目前为止所做的:
class RevealLabel : System.Windows.Forms.Label
{
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
const int GradWidth = 7;
Rectangle r = new Rectangle(e.ClipRectangle.X, e.ClipRectangle.Y,
GradWidth, e.ClipRectangle.Height);
GraphicsPath p = new GraphicsPath();
using (SolidBrush bs = new SolidBrush(this.ForeColor))
{
using (LinearGradientBrush bg = new LinearGradientBrush(new Rectangle(0, 0, GradWidth, e.ClipRectangle.Height),
this.ForeColor,
this.BackColor,
LinearGradientMode.Horizontal))
{
for (int i = 0; i < e.ClipRectangle.Width; i += GradWidth)
{
r.X = i;
p.AddString(this.Text, this.Font.FontFamily, (int)this.Font.Style, this.Font.Size,
r, StringFormat.GenericDefault);
e.Graphics.FillPath(bg, p);
e.Graphics.Flush();
long TickStop = DateTime.Now.AddSeconds(0.2).Ticks;
while (DateTime.Now.Ticks < TickStop)
{
System.Windows.Forms.Application.DoEvents();
}
e.Graphics.FillPath(bs, p);
}
}
}
e.Graphics.Flush();
}
}
不确定我是否在正确的轨道上,因为这呈现的只是一个可怕的混乱。一个甚至没有逐渐显示在屏幕上的混乱,而是似乎在后台处理所有内容然后只用最终结果更新屏幕。
所以,我的问题是双重的:
渲染像素/矩形区域的正确方法是什么?我会在每次迭代时附加到右边?
如何让它在每次抽奖时更新到屏幕,而不仅仅是完成后的一个块?
(注意:我也尝试在后台线程中绘画,但是一直保持ArgumentException,我认为因为Graphics对象在离开绘制处理程序方法后很快就会失去可用状态。)
答案 0 :(得分:1)
尝试使用计时器:
public class RevealLabel : Label {
private System.Windows.Forms.Timer revealTimer = new System.Windows.Forms.Timer();
private int paintWidth = 0;
private int paintIncrement = 7;
public RevealLabel() {
this.DoubleBuffered = true;
revealTimer.Interval = 200;
revealTimer.Tick += new EventHandler(revealTimer_Tick);
}
void revealTimer_Tick(object sender, EventArgs e) {
paintWidth += paintIncrement;
if (paintWidth > this.ClientSize.Width) {
revealTimer.Enabled = false;
} else {
this.Invalidate();
}
}
protected override void OnPaint(PaintEventArgs e) {
if (revealTimer.Enabled) {
e.Graphics.Clear(this.BackColor);
Rectangle r = new Rectangle(0, 0, paintWidth, this.ClientSize.Height);
TextRenderer.DrawText(e.Graphics, this.Text, this.Font, r, Color.Black, Color.Empty, TextFormatFlags.Left | TextFormatFlags.VerticalCenter);
} else {
paintWidth = 0;
revealTimer.Start();
}
}
}
我可能会继承Panel
而不是Label
,因为无论如何你自己都在做所有的绘画。
如果您希望标签始终具有动画效果,请将this.Invalidate()
调用移至IF块之外的Tick
事件中。
答案 1 :(得分:0)
在敲开这个之后,我终于找到了解决方案,在这里:
public class RevealLabel : System.Windows.Forms.Control
{
private const int GradWidth = 5;
private const int DrawDelay = 20;
private int lcBackgroundPaintThreadId;
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
e.Graphics.Clear(this.BackColor);
if (this.DesignMode)
{
using (SolidBrush bs = new SolidBrush(this.ForeColor))
{
e.Graphics.DrawString(this.Text, this.Font, bs, 0, 0);
}
}
else
{
System.Threading.ThreadPool.QueueUserWorkItem(QueuePaintStep, this.ClientRectangle.X);
}
}
private void QueuePaintStep(object state)
{
lcBackgroundPaintThreadId = System.Threading.Thread.CurrentThread.ManagedThreadId;
System.Threading.Thread.Sleep(DrawDelay);
if (System.Threading.Thread.CurrentThread.ManagedThreadId == lcBackgroundPaintThreadId)
{
int x = (int)state;
if (x < this.ClientRectangle.Width)
{
Rectangle r = new Rectangle(x, this.ClientRectangle.Y, GradWidth, this.ClientRectangle.Height);
if (System.Threading.Thread.CurrentThread.ManagedThreadId != lcBackgroundPaintThreadId) return;
using (LinearGradientBrush bg = new LinearGradientBrush(new Rectangle(0, 0, GradWidth, r.Height),
this.ForeColor,
this.BackColor,
LinearGradientMode.Horizontal))
{
this.Invoke(AsyncPaintCommon, this, bg, r);
}
System.Threading.Thread.Sleep(DrawDelay);
if (System.Threading.Thread.CurrentThread.ManagedThreadId != lcBackgroundPaintThreadId) return;
using (SolidBrush bs = new SolidBrush(this.ForeColor))
{
this.Invoke(AsyncPaintCommon, this, bs, r);
}
if (System.Threading.Thread.CurrentThread.ManagedThreadId != lcBackgroundPaintThreadId) return;
QueuePaintStep(x + GradWidth);
}
}
}
private delegate void AsyncPaintDelegate(RevealLabel l, Brush b, Rectangle r);
private static Delegate AsyncPaintCommon = new AsyncPaintDelegate((RevealLabel l, Brush b, Rectangle r) =>
{
using (Graphics g = l.CreateGraphics())
{
g.SetClip(r);
g.DrawString(l.Text, l.Font, b, 0, 0);
}
});
}
欢迎任何反馈。