我有下面的代码,它是选取框标签的实现。我希望选取框标签在计算机上以最有效的速度运行,同时在不同的计算机上保持恒定的速度。我希望最小化跳过的“帧”数量,以便程序充分利用正在运行的计算机。但与此同时,我不一定要消耗 100% 的 CPU(这些陈述是否相互矛盾?我不确定)。
目前,我为动画循环的每次迭代都睡了 10 毫秒。这对我来说感觉很浪费,而且似乎它可能会减慢可能需要额外 10 毫秒的较慢计算机上的动画。我不确定在 sleep 方法中使用的最佳价值是什么,或者我是否应该睡觉。我已经阅读了一些关于 Sleep(0) 和 Sleep(1) 以及 Yield 和 SpinWait 的内容,但我无法理解这一切。
过多地调用 Invalidate 也是一件坏事吗?我可以通过调用它来超载它吗?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.ComponentModel;
using System.Diagnostics;
using Timer = System.Timers.Timer;
using System.Threading;
namespace Scoreboard
{
public class MarqueeLabel : Label
{
private float _marqueeOffset;
private float _marqueeMeasurement;
public MarqueeLabel()
{
UseCompatibleTextRendering = true;
this.SetStyle(ControlStyles.DoubleBuffer, true);
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.UserPaint, true);
Thread t = new Thread(ThreadRun);
t.IsBackground = true;
t.Start();
}
public void ThreadRun()
{
long time = DateTime.Now.Ticks;
long diff = 0;
while (true)
{
float step = -((float)diff / (20 * TimeSpan.TicksPerMillisecond)); //change "frame" based on the elapsed time
_marqueeOffset = _marqueeOffset >= -_marqueeMeasurement ? _marqueeOffset + step : Width;
Invalidate();
Thread.Sleep(10); // how long should i wait here?
long temp = DateTime.Now.Ticks;
diff = temp - time;
time = temp;
}
}
protected override void OnPaint(PaintEventArgs e)
{
StringFormat stringFormat = new StringFormat();
stringFormat.FormatFlags = StringFormatFlags.NoClip | StringFormatFlags.NoWrap;
stringFormat.Trimming = StringTrimming.None;
stringFormat.Alignment = StringAlignment.Near;
Rectangle rect = ClientRectangle;
rect.X += (int)_marqueeOffset;
e.Graphics.DrawString(Text, Font, new SolidBrush(ForeColor), rect, stringFormat);
}
protected override void OnTextChanged(EventArgs e)
{
base.OnTextChanged(e);
MeasureText();
}
protected override void OnFontChanged(EventArgs e)
{
base.OnFontChanged(e);
MeasureText();
}
void MeasureText()
{
_marqueeMeasurement = CreateGraphics().MeasureString(Text, Font).Width;
}
}
}