我有一个我已经子类化并且设置DoubleBuffered
为真的面板,我经常需要刷新绘图但是它会闪烁并且不知道为什么。
private delegate void MyDelegate();
public void heartBeat()
{
while (true)
{
if (map.processNubots(rules))
{
if (this.InvokeRequired)
{
this.Invoke((MyDelegate)delegate
{
//drawPanel.SuspendLayout();
drawPanel.Refresh();
displayGrid();
//drawPanel.ResumeLayout();
});
}
Thread.Sleep(500);
}
else
{
break;
}
}
}
public void displayGrid()
{
int i = 0;
foreach (DictionaryEntry pair in map)
{
Monomer current = (Monomer)pair.Value;
drawMonomers(current.getLocation(), current.getState());
i++;
}
}
public void drawMonomers(Point location, string state)
{
...
SolidBrush sb = new SolidBrush(mycolor);
SolidBrush sbt = new SolidBrush(Color.Black);
Graphics g = drawPanel.CreateGraphics();
Font text = new Font("Arial", scale / 2);
Pen pen = new Pen(Color.Black, 1);
pen.Alignment = PenAlignment.Inset;
g.FillEllipse(sb, offSet + ((location.Y * scale) / 2) + (location.X * scale), offSet + (-location.Y * scale), scale, scale);
g.DrawEllipse(pen, offSet + ((location.Y * scale) / 2) + (location.X * scale), offSet + (-location.Y * scale), scale, scale);
g.DrawString(state, text, sbt, (offSet + ((location.Y * scale) / 2) + (location.X * scale)) + scale / 6, (offSet + (-location.Y * scale)) + scale / 6);
sb.Dispose();
sbt.Dispose();
pen.Dispose();
}
因此,在每次“计算”之后并向我想象中的网格添加了一些东西,我需要更新面板以在我的网格上显示这个新项目。我已经尝试在displayGrid()
函数之前使面板无效,但它似乎会导致更多的闪烁。
当前正在一个单独的线程上调用heartbeat()
函数。
这是我的新Panel
课程。
public class Display : Panel
{
public Display()
{
this.DoubleBuffered = true;
}
}
答案 0 :(得分:9)
Graphics g = drawPanel.CreateGraphics();
使用CreateGraphics()和启用双缓冲是最糟糕的组合。 CreateGraphics()为您提供直接绘制到屏幕的Graphics对象。 Double-buffering设置一个Graphics对象,该对象绘制到一个位图,即双缓冲中使用的缓冲区。然后在绘制周期结束时将位图渲染到屏幕。
所以你的代码中发生的事情是你直接绘制屏幕,你几乎看不到它,但是如果它足够慢的话就可见。然后就在那之后,你从未画过的缓冲区会被绘制掉。这抹去了你之前画的东西。净效果是重闪烁,您的绘画输出只能看到几毫秒。
使用CreateGraphics()是错误的。 总是想要通过您从Paint事件获得的e.Graphics对象进行渲染,以便渲染到缓冲区。将Graphics对象传递给drawMonomers()方法。因此:
public void drawMonomers(Graphics g, Point location, string state) {
// Etc...
}
private void Display1_Paint(object sender, PaintEventArgs e) {
//...
drawMonomers(e.Graphics, loc, state);
}
通常,CreateGraphics()具有非常有限的用途。当你想要直接绘制到屏幕时,你只能使用它,你可以买得起你想要消失的任何东西。这通常仅适用于具有不断运行的渲染循环的程序,以高速率生成新输出,例如每秒20帧以上。就像一个视频游戏。
答案 1 :(得分:0)
添加AllPaintingInWmPaint样式将阻止重绘背景。
我以前遇到过这篇文章,发现它非常有帮助。 How do I enable double-buffering of a control using C# (Windows forms)?
它可能过度杀伤,但它有效。我注意到用户的一件事是,如果 运行得更顺畅,更快,就是。 (即使确实需要更长的时间)
答案 2 :(得分:0)
尝试用PictureBox替换面板。这对我有用。