C# 如何修复重画时面板闪烁?

C# 如何修复重画时面板闪烁?,c#,panel,C#,Panel,我有一个面板,我已经将其子类化为并设置为双缓冲真,我经常需要刷新图形,但它会闪烁,不知道为什么 private delegate void MyDelegate(); public void heartBeat() { while (true) { if (map.processNubots(rules)) { if (this.InvokeRequired)

我有一个面板,我已经将其子类化为并设置为
双缓冲
真,我经常需要刷新图形,但它会闪烁,不知道为什么

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()
函数当前正在单独的线程上调用

这是我新的
面板

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

    }
}

添加AllPaintingInWmPaint样式将防止重新绘制背景

我以前看过这篇文章,觉得很有帮助

这可能有点过分,但它确实有效。我注意到用户的一件事是,如果它看起来运行得更平稳、更快,那么它就是。(即使它确实需要更长的时间)

使用CreateGraphics()和启用双缓冲是最糟糕的组合。CreateGraphics()为您提供一个直接绘制到屏幕的图形对象。双缓冲设置绘制位图的图形对象,位图是双缓冲中使用的缓冲区。然后在绘制周期结束时将位图渲染到屏幕上

因此,代码中的情况是直接绘制屏幕,如果速度足够慢,屏幕几乎看不见,但可以看到。然后就在那之后,你从未画过的缓冲区被画上了。这抹掉了你以前画的东西。净效果为heavy闪烁,绘制输出仅在几毫秒内可见

使用CreateGraphics()是错误的。您总是希望通过从Paint事件中获得的e.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多帧的高速率生成新输出。像电子游戏一样。

试着用图片盒替换面板。这对我来说很有效。

每一次省略都会改变每一次计算吗?不,不会,但是,在这一点上,我正在重新绘制它们。我确实需要在未来进行优化,只改变需要更新的内容。但它可能在20号左右的椭圆开始闪烁,这似乎很快就会与之相关。在我的程序中,我必须在绘制单体之前计算一些相互作用,我如何才能继续处理,然后用这个方法重画?把你计算的任何东西都存储在你的类的字段中,这样你就可以在画画的时候随时使用它们。如果计算尚未完成,则不要调用drawMonomers()。完成后立即调用面板的Invalidate()方法。此计算正在循环。计算网格->绘制中的对象,计算网格->绘制中的对象。据我所知,油漆只在首次装入面板时进行。油漆是在需要时进行的。或者在强制执行时,就像在代码段中调用Refresh()所做的那样。
public void drawMonomers(Graphics g, Point location, string state) {
   // Etc...
}

private void Display1_Paint(object sender, PaintEventArgs e) {
   //...
   drawMonomers(e.Graphics, loc, state);
}