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 thePanel's BackgroundImage
. All drawing fromN+1
will still be drawn onto the panel's surface in thePaint
event. When you reach2*N
you create another version of the caching image, start surface drawing at2*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
C# MACro Definitions in Preprocessor
Extracting Text from PDFs in C#
How to Print a Text File on Thermal Printer Using Printdocument
How to Format 07/03/2012 to March 7Th,2012 in C#
System.Io.Filestream Fileaccess VS Fileshare
Passing Parameters to Xslt Stylesheet via .Net
Sqlite .Net Performance, How to Speed Up Things
Open File in Exclusive Mode in C#
How to Set Chrome Preferences Using Selenium Webdriver .Net Binding
How to Draw a Rounded Rectangle in C#
Wpf Dispatcher {"The Calling Thread Cannot Access This Object Because a Different Thread Owns It."}
What Does the Tilde Mean in an Expression
Formatting a C# String with Identical Spacing in Between Values
Linq to Objects - Return Pairs of Numbers from List of Numbers