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

标签 c# panel

我有一个我已经子类化的面板并将 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 对象,即双缓冲中使用的缓冲区。然后在绘制周期结束时将位图渲染到屏幕上。

所以在您的代码中发生的事情是您直接绘制屏幕,​​如果它足够慢,您几乎看不到但可以看到。然后就在那之后,你永远不会绘制的缓冲区被绘制。这会抹去你之前画的东西。最终效果是严重闪烁,您的绘画输出仅在几毫秒内可见。

使用 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+ 帧的高速率产生新输出。就像一个电子游戏。

关于c# - 重绘时如何修复面板闪烁?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16882921/

相关文章:

R:levelplot(轮廓中缺少一些值)

java - 如何防止 JDialog 在 gnome-panel(Linux) 中显示?

layout - 当子面板溢出时,在父面板上自动滚动。

java - Gui 不绘制面板

c# - 进程需要按 <enter> 才能继续。可以使用 Mono GTK# 吗?

c# - 使用c#并行下载多个文件

c# - 在 WPF 中我需要有一组绘图对象的集合

c# - 从JavaScript设置runat =“server”

c# - 如何创建具有不同直径的 3D 管

c++ - gnome 回退小程序 C++