重绘时如何修复面板闪烁?

我有一个我已经子类化的面板并将DoubleBuffered设置DoubleBuffered true,我经常需要刷新绘图,但它闪烁并且不知道为什么。

 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; } } 

  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帧以上。 就像一个video游戏。

添加AllPaintingInWmPaint样式将阻止重绘背景。

我以前遇到过这篇文章,发现它非常有帮助。 如何使用C#(Windows窗体)启用控件的双缓冲?

可能有点矫枉过正,但它确实有效。 我注意到用户的一件事是,如果它看起来运行得更顺畅,速度更快。 (即使确实需要更长的时间)