Tuesday, July 12, 2011

Preventing Flicker with GDI+ drawing in C#

In C#, the OnPaintBackground method is called before the OnPaint event and it draws the background color for the entire view. If you are already drawing the background in the OnPaint event, then this process will cause flicker. You can override the OnPaintBackground and just do nothing in it to prevent the flicker:
protected override void OnPaintBackground(PaintEventArgs pevent)
{
// do nothing
}

8 comments:

VakarimaZ said...

The easier way is to enable Double Buffer for your form/control.
Example:
class BufferedPanel : Panel
{
public BufferedPanel()
{
this.DoubleBuffered = true;
}
}

srego said...

True in some cases, but in my case I am bliting the entire view on every OnPaint, so double buffer would be a waste of both resources and performance.

Mahmoud Hanafy said...

Thanks much, was really helpful.
I had an issue with flicker in GDI+, and your solution of overriding paint background worked like charm.

Thank again, and appreciated.

DieDaily said...

srego, I disagree on both points. Double buffering does, as the name suggests, double the amount of RAM dedicated to painting your form (or panel) but it's not a "waste" of those resources because it defeats flickering (and the vast hogging of kernal resources associated with it). Much more importantly, performance is in every way enhanced by double buffering. There are no kernel calls made in mid-render when double buffering is employed. So, while your claim that resources are "wasted" is at least true in the sense that more RAM is actually used up, I don't think there is any sense in which performance is degraded, or "wasted". Quite the opposite, in fact.

srego said...

If you are replacing the image on each update, double buffering is definitely a waste. Memory is a resource, and your copy to the buffer has to be done somewhere. Performance would definitely be degraded because you are drawing to the buffer which then has to be blitted to the screen. In the example I describe, you have to render the entire image in memory which is then blitted to the screen. If you double buffer, it would be rendered in memory, blitted to the buffer, then blitted to the screen. Two blits versus one.

Viktor Engelmann said...

srego, your argument is nonsense. Double buffering means that you can do slow drawing on the first buffer, while screen-updates are done using the second buffer. Then - when you are done drawing on the first buffer, copy the first buffer to the second one (which is very fast).
With only one buffer, screen-updates must wait until you are done with your slow drawing routines (and this is what causes the flickering).

Viktor Engelmann said...

srego, your argument is nonsense. Double buffering means that you can do slow drawing on the first buffer, while screen-updates are done using the second buffer. Then - when you are done drawing on the first buffer, copy the first buffer to the second one (which is very fast).
With only one buffer, screen-updates must wait until you are done with your slow drawing routines (and this is what causes the flickering).

Viktor Engelmann said...

And by the way - Just yesterday I got rid of screen-flickering by turning on double buffering (so your argument is not only theoretically nonsense, but also practically).

As to the topic: only setting this.DoubleBuffered = true; is not sufficient. You also need to do

this.SetStyle(ControlStyles.OptimizedDoubleBuffer |
ControlStyles.UserPaint |
ControlStyles.AllPaintingInWmPaint,
true);