我目前正在开展一个项目,我必须使用GDI +(System.Drawing
)。我正在尝试制作一个带有动态neeldes的多功能仪表(一个类似钟表的轮子)。
我不想每帧都绘制背景图像(带有所有标记)。我现在解决这个问题的方法是将它设置为图形“容器”的背景图像,这是一个面板(请记住这一点,我可能不得不这样做。)
然后我画针。针目前每秒更新25次(我可能会优化它,以便它只在必要时更新)。但问题是,我必须在开始使用新帧之前清除缓冲区,导致背景图像被缓冲区的背景颜色覆盖。显然我不想要这个。
我尝试将缓冲区的背景颜色设置为Color.Transparent
,但是根据父级的透明度键(在我的情况下,它会变成黑色),它会为缓冲区提供一种颜色。
以下是我当前用于绘制针的代码(在Wheel
类中):
/// <summary>
/// Draws the wheel and the needles.
/// </summary>
public void Draw()
{
Graphics.Clear(Color.Transparent);
// Draws all needles, works fine
foreach (Needle Ndl in Needles)
{
Ndl.Draw(ref this.Graphics);
}
// Draws the little circle in the center of the wheel. Looks only.
Graphics.FillEllipse(new Pen(Color.White).Brush, new Rectangle(120, 120, 16, 16));
}
是的,我已遵循Stack Overflow规则,我完成了我的作业。其他人通过使用BitBlt每帧绘制图像来解决它,这是我的大脑理解的方法。
我对此非常开放,所以如果你认为我应该使用BitBlt,你知道我在哪里可以找到一些相关的深入例子,我肯定会用BitBlt来做。当然,如果有不使用BitBlt的解决方案,或者无论如何在这里使用它都没有意义,那会更好。
是否可以使缓冲区的背景透明,或者我应采取完全不同的方法?
注意:我最好不要使用XNA,因为此应用程序主要用于简单/旧计算机上的维护,所以我不想与可再发行组件有任何关系。
答案 0 :(得分:1)
您可以将基本图像放在PictureBox中。然后你的代码可以处理PictureBox的Paint事件来绘制你的针。这样你就不必担心Graphics.Clear()的透明度或运行缓慢:你的代码只需要计算针的位置。
作为一个快速测试,我写了一个小形式的应用程序,创建一个时针(红色),秒针(贪婪)和毫秒手(蓝色)的时钟。分针得不到尊重,因此未显示。背景是在GIMP中创建的黑色圆角矩形的图像。
为了模拟您的环境,我添加了一个间隔为10毫秒(100周期/秒)的计时器。处理事件Timer.Tick时,强制重绘PictureBox。
我手动编辑代码,只留下毫秒手的代码:
public Form1()
{
InitializeComponent();
pictureBox1.Paint += new PaintEventHandler(pictureBox1_Paint);
Center = new PointF((float)pBox1.Width / 2, (float)pBox1.Height / 2);
MillisecondLength = (float)pBox1.Width / 4; //length of millisecond hand
timer1.Interval = 10;
timer1.Enabled = true;
timer1.Tick += new EventHandler(timer1_Tick);
}
PointF Center;
float MillisecondLength;
Pen MillisecondsPen = new Pen(Brushes.Blue, (float)3);
double HALF_PI = Math.PI / 2;
double TWO_PI = 2 * Math.PI;
double millisecondHandAngle(DateTime dt)
{
//12 o'clock is at the top! (- PI / 2)
return TWO_PI * dt.Millisecond / 1000 - HALF_PI;
}
void pBox1_Paint(object sender, PaintEventArgs e)
{
DateTime dt = DateTime.Now;
double mangle = millisecondHandAngle(dt);
SizeF millisecondOffset = new SizeF(
(float)(MillisecondLength * Math.Cos(mangle)),
(float)(MillisecondLength * Math.Sin(mangle))
);
PointF endMillisecond = PointF.Add(Center, millisecondOffset);
e.Graphics.DrawLine(MillisecondsPen, Center, endMillisecond);
}
void timer1_Tick(object sender, EventArgs e)
{
pBox1.Invalidate();
}
虽然代码中没有显示,但是我添加了一个System.Diagnostics.Stopwatch和一个计数器变量来计算实际帧速率,这在我的旧笔记本电脑上达到了大约64帧/秒的峰值。即使您将计时器间隔设置得非常小,也会有最大重绘率。