How to eliminate panel flicker when redrawing?

I have a panel that I have subclassed and set DoubleBuffered true, I need to constantly update the drawing, but it flickers and has 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(); } 

Therefore, after each β€œcalculation” and added something to my imaginary grid, I need to update the panel to show this new element in my grid. I tried to invalidate the panel in front of the displayGrid() function, but it seems even more flickering.

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

Here is my new Panel class.

 public class Display : Panel { public Display() { this.DoubleBuffered = true; } } 
+3
source share
3 answers
  Graphics g = drawPanel.CreateGraphics(); 

Using CreateGraphics () and enabling double buffering is the worst possible combination. CreateGraphics () provides a Graphics object that draws directly on the screen. Double buffering sets a Graphics object that draws a bitmap image, a buffer used in double buffering. It then displays the bitmap on the screen at the end of the drawing cycle.

So what happens in your code is that you draw the screen directly, something that you can hardly see but see if it is slow enough. Then right after this buffer, which you never draw, is drawn. What wipes what you painted before. The net effect is a heavy flicker with your image visible only for a few milliseconds.

Using CreateGraphics () was a mistake. You always want to render through the e.Graphics object that you get from the Paint event so that you display the buffer. Pass this Graphics object to your drawMonomers () method. In this way:

 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 utility. You only ever use it when you want to paint right on the screen, and you can afford everything you painted to disappear. This is usually useful only in the form of a program in which the visualization cycle is constantly working, creating a new output with a high speed, for example, 20+ frames per second. Like a video game.

+9
source

Adding the AllPaintingInWmPaint style will prevent the background from being redrawn.

I came across this post before and found it quite useful. How to enable double buffering of a control using C # (windows form)?

It may be redundant, but it works. One thing I noticed with users is that it works more smoothly and faster. (even if it really takes a little longer)

0
source

Try replacing the panel with a PictureBox. It worked for me.

0
source

Source: https://habr.com/ru/post/1393734/


All Articles