C#, double buffer in WinForms?

4.4k views Asked by At
        private void button3_Click(object sender, EventArgs e)
    {

        this.DoubleBuffered = true;

            for (int i = 0; i < 350; i++)
            {
                using (Graphics g = this.CreateGraphics() )
                {
                    g.Clear(Color.CadetBlue);
                    g.DrawImage(Properties.Resources._256, 100, 100, i-150, i-150);
                }
            }
    }

Yet thought I have the DoubleBuffered set to true, the image still flickers. Any ideas what am I doing wrong? Thanks!

3

There are 3 answers

0
Ed Swangren On BEST ANSWER

As Neil noted, you don't need to (and shouldn't) create a new Graphics object in each iteration of the loop. These are relatively expensive resources and should not be created willy nilly.

Also, you shouldn't be painting like that inside of a button Click handler by calling CreateGraphics. It can lead to problems, most notably your drawing being "undone" when the paint handler is invoked (i.e., every time the window is receives a WM_PAINT message and is refreshed). You should do all of your painting by overriding OnPaint and simply call Invalidate() when you need to update your form.

As for the flickering, setting DoubleBuffered to true will usually take care of it, but rolling your own double buffering is trivial. Give it a try. Also realize that drawing in a loop like that probably isn't what you want to do. Use a timer if you want to update once per some interval. Your code is being executed as fast as the loop can execute, which is not usually desirable.

private void someTimer_Tick( ... )
{
    Invalidate();
}
protected override void OnPaint( PaintEventArgs e )
{
    using( var tempBmp = new Bitmap( ... ) )
    using( var g = Graphics.FromImage( tempBmp ) )
    {
        // draw to tempBmp
        e.Graphics.DrawImage( tempBmp, new Point( 0, 0 ) );
    }
}
2
Neil N On

The problem is you are creating a new graphics object on each iteration of the loop

Move the for statement within the using statement, and you should see a dramatic performance increase:

using (Graphics g = this.CreateGraphics() )
{
     for (int i = 0; i < 350; i++)
     {
        g.Clear(Color.CadetBlue);
        g.DrawImage(Properties.Resources._256, 100, 100, i-150, i-150);
     }
}

That, and it may also be a good idea to move the Resource file you are loading into a local variable.

0
Hans Passant On

Double-buffering is only enabled for the Paint event. You are directly drawing to the screen with CreateGraphics(), the g.Clear() call is very noticeable since it instantly erases the drawn image. Not drawing in the Paint event or OnPaint method is almost always a mistake.