Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
509 views
in Technique[技术] by (71.8m points)

c# - How to fix panel flickering when redrawing?

I have a panel that I've subclassed to and have set DoubleBuffered true, I constantly need to refresh the drawing but it flickers and have no idea why.

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

So after every "computation" and have added something to my imaginary grid, I need to update the panel to show this new item on my grid. I have tried invalidating the panel right before the displayGrid() function but it seems to cause even more flickering.

The heartbeat() function is currently being called on a separate thread.

Here is my new Panel class.

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

    }
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
    Graphics g = drawPanel.CreateGraphics();

Using CreateGraphics() and turning on double-buffering is the worst possible combination. CreateGraphics() gives you a Graphics object that draws directly to the screen. Double-buffering sets up a Graphics object that draws to a bitmap, the buffer used in double-buffering. Then renders the bitmap to the screen at the end of the paint cycle.

So what happens in your code is that you draw the screen directly, something you can barely see but visible if it is slow enough. Then right after that the buffer that you never draw into gets painted. Which wipes out what you drew before. The net effect is heavy flicker with your paint output visible for only a handful of milliseconds.

Using CreateGraphics() was the mistake. You always want to render through the e.Graphics object that you get from the Paint event so you'll render to the buffer. Pass that Graphics object to your drawMonomers() method. Thus:

public void drawMonomers(Graphics g, Point location, string state) {
   // Etc...
}

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

In general, CreateGraphics() has very limited usefulness. You only ever use it when you want to draw to the screen directly and you can afford for whatever you draw to disappear. That is typically only useful in the kind of program that has a render loop that constantly runs, producing new output at a high rate like 20+ frames per second. Like a video game.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...