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

Dav*_*vez 4 c# panel

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

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();
    }
Run Code Online (Sandbox Code Playgroud)

因此,在每次"计算"之后并向我想象中的网格添加了一些东西,我需要更新面板以在我的网格上显示这个新项目.我已经尝试在displayGrid()功能之前使面板无效,但它似乎导致更多的闪烁.

heartbeat()函数当前正在一个单独的线程上调用.

这是我的新Panel课程.

public class Display : Panel
{
    public Display()
    {
        this.DoubleBuffered = true;

    }
}
Run Code Online (Sandbox Code Playgroud)

Han*_*ant 10

    Graphics g = drawPanel.CreateGraphics();
Run Code Online (Sandbox Code Playgroud)

使用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);
}
Run Code Online (Sandbox Code Playgroud)

通常,CreateGraphics()的用处非常有限.当你直接绘制到屏幕上时,你只能使用它,你可以买得起你想要消失的任何东西.这通常仅适用于具有不断运行的渲染循环的程序,以高速率生成新输出,例如每秒20帧以上.就像一个视频游戏.