How to Double Buffer a Panel

Double buffering with Panel

I should have posted my solution a long time ago...

Well, here is my solution:

Bitmap buffer = new Bitmap(screenWidth, screenHeight);//set the size of the image
System.Drawing.Graphics gfx = Graphics.FromImage(buffer);//set the graphics to draw on the image
drawStuffWithGraphicsObject(gfx);//draw
pictureBox1.Image = buffer;//set the PictureBox's image to be the buffer

Makes me feel like a complete idiot for finding this solution years after asking this question.

I have tried this with a Panel, but it has proven to be slower when applying the new image. Somewhere I had read, that it is better to use Panel instead of PictureBox. I don't know if I have to add something to the code to speed things up for the Panel, though.

How to make double buffering for a panel?

To get rid of flickering, I use the following settings to configure how a control behaves:

base.DoubleBuffered = true;

SetStyle(ControlStyles.AllPaintingInWmPaint, true);
SetStyle(ControlStyles.ResizeRedraw, true);
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
UpdateStyles();

I call this in the constructor of a Control-derived class. I'm not sure whether this also works for forms, too, but I would imagine that it does.

The drawing is then done in void OnPaintBackground(PaintEventArgs e) (erasing the client area) and void OnPaint(PaintEventArgs e) (actual drawing).

Should Double Buffering be done on a panel where I'm already drawing from a Bitmap, to minimize flicker?

The optimal solution will mostly depend on what you draw, how many operations, how many pixels involved and the total size of the drawing surface.

One common example is a drawing program, where the user piles strokes upon strokes, each consisting of hundreds of points..

In general it is recommended to let the system take care of double-buffering the control you draw on. It will do a better job than you can hope for..

So you should re-draw in the Paint event and not try to implement your own buffered bitmap drawing in order to get rid of flicker.

The flicker will go away but with a huge number of drawing operations this will be slow and cause lags.

To avoid lags you can combine the best of both methods:

  • draw the graphics until they get too many; it depends on the drawing calls (basically the number of pixels involved) and the speed of your system whether you can afford a few hundred or tens of thousands of drawing calls before you notice lags, say after N calls.

  • Then cache the first N drawing calls by drawing into a bitmap which you then set as the Panel's BackgroundImage. All drawing from N+1 will still be drawn onto the panel's surface in the Paint event. When you reach 2*N you create another version of the caching image, start surface drawing at 2*N+1 and so forth..

Double buffering doesn't work on a panel?

Delete the line defining the graphics1 field.

Perform ALL painting in the override of OnPaint, using the Graphics object passed in with the PaintEventArgs object. Use the methods Invalidate(), Refresh(), and Update() to control the timing of repainting from other code.

Callback if you encounter any specific difficulties with this design.

How to double buffer .NET controls on a form?

Here's a more generic version of Dummy's solution.

We can use reflection to get at the protected DoubleBuffered property, and then it can be set to true.

Note: You should pay your developer taxes and not use double-buffering if the user is running in a terminal services session (e.g. Remote Desktop) This helper method will not turn on double buffering if the person is running in remote desktop.

public static void SetDoubleBuffered(System.Windows.Forms.Control c)
{
//Taxes: Remote Desktop Connection and painting
//http://blogs.msdn.com/oldnewthing/archive/2006/01/03/508694.aspx
if (System.Windows.Forms.SystemInformation.TerminalServerSession)
return;

System.Reflection.PropertyInfo aProp =
typeof(System.Windows.Forms.Control).GetProperty(
"DoubleBuffered",
System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Instance);

aProp.SetValue(c, true, null);
}

How do I enable double-buffering of a control using C# (Windows forms)?

In the constructor of your control, set the DoubleBuffered property, and/or ControlStyle appropriately.

For example, I have a simple DoubleBufferedPanel whose constructor is the following:

this.DoubleBuffered = true;
this.SetStyle(ControlStyles.UserPaint |
ControlStyles.AllPaintingInWmPaint |
ControlStyles.ResizeRedraw |
ControlStyles.ContainerControl |
ControlStyles.OptimizedDoubleBuffer |
ControlStyles.SupportsTransparentBackColor
, true);

Slow double buffering method

This is NOT how painting works in Swing -> pg = panel.getGraphics(); this is a horribly bad idea. You are fighting between the passive rendering engine of Swing and your attempt to paint to a "snap shot" of the component.

Swing components are, when you use them properly, double buffered internally, but, you need to be working with the API.

Start by having a look at Performing Custom Painting and Painting in AWT and Swing for more details about how painting works in Swing

Basically, what's happening is, you are using the results from getGraphics to paint to the panel, the RepaintManager is coming along and decides it needs to update your component and repaints it, which produces a blank panel, repeat really fast. This is what's causing your flickering. In Swing, you do not control the paint process, you can only ask to be notified when a paint cycle occurs (overriding paintComponent for example) and make requests to the painting system that a repaint should occur, but it's up to the paint system to actually decide WHEN that paint cycle occurs.

Instead, start by overriding the panel's paintComponent method and perform ALL your custom painting within it. Use repaint to request that the component be updated.

If you "really" need a active painting process, then have a look at BufferStrategy and BufferStrategy and BufferCapabilities, which provides you the means to directly control when the output is pushed to the screen device.



Related Topics



Leave a reply



Submit