Double Buffering and Flicker-Free Drawing in GDI+

This article has been excerpted from book "GraphicsProgramming with GDI+".

Drawing on the Web works differently from drawing in the Windows Forms. On the Web we have many limitations, one of which is no pixelwise drawing support in the Web browser. Our approach was to convert our graphics objects into a temporary bitmap image and view the image in a Web browser.

Double buffering is a similar concept. You may have seen one of the frequently asked questions on GDI+ discussion forums: "How do we create flicker-free drawings"? The double buffering technique is used to provide faster, smoother drawings by reducing flicker. In this technique, all objects are drawn on an off-screen canvas with the help of a temporary image and a Graphics object. The image is then copies to the control. If the drawing operation is small and includes drawing only simple objects such as rectangle or lines, there is no need for double buffering (it may even degrade performance). If there are many calculations or drawn elements, performance and appearance may be greatly improved through the use of double buffering.

To provide the point, let's write an example. Listing 13.8 gives the code for a drawing method that draws several lines.

LISTING 13.8: The DrawLine method

private void DrawLine (Graphics g)
{
float width = ClientRectangle.Width;
float height = ClientRectangle.Height;
float partX = width / 1000;
float partY = height / 1000;
for (int i =0; i<10000; i++)
{
g.DrawLine (Pens.Blue,
0, height - (partY * i),
partX * i, 0);
g.DrawLine (Pens.Green,
o,
height - (partY * i),
(width) - partX * i, 0);
g.DrawLine (Pens.Red, 0,
partY * i,
(width) - partX * i, o);
}
}

To test our application, we will call it from a button click. The code for a button click event handler is given in Listing 13.9.

LISTING 13.9: Calling the DrawLines method

            //Create a Graphics object for "this"
            Graphics g = this.CreateGraphics();
            g.Clear(this.BackColor);
            //Draw lines
            DrawLines(g);
            //Dispose of object
            g.Dispose();

Figure 13.4 shows the output from Listing 13.9.

Now let's draw the same lines using a Bitmap object. We create a temporary Graphics object from a temporary image and call its draw and fill methods. Instead of calling DrawLine with respect to a form, we call DrawImage, which draws the image generated by the DrawLine method.

Figure 13.4.jpg

FIGURE 13.4: Drawing lines in a loop

As Listing 13.10 shows, we create a Bitmap object in a buffer and send the entire buffer all at once using DrawImage. We add the code given in Listing 13.10 on the Bitmap Draw button click event handler.

LISTING 13.10: Using double buffering to draw

            Graphics g = this.CreateGraphics();
            g.Clear(this.BackColor);
            //Create a Bitmap object with the size of the form
            Bitmap curBitmap = new Bitmap(ClientRectangle.Width, ClientRectangle.Height);
            //Create a temporary Graphics object from the bitmap
            Graphics g1 = Graphics.FromImage(curBitmap);
            //Draw lines on the temporary Graphics object
            DrawLines(g1);
            //Call DrawImage of Graphics and draw bitmap
            g.DrawImage(curBitmap, 0, 0);
            //Dispose of objects
            g1.Dispose();
            curBitmap.Dispose();
            g.Dispose();


Comparing the two methods given in Listing 13.9 and 13.10 reveals a significant difference in drawing performance. In Listing 13.9, drawing begins as soon as we hit the Simple Draw button and continues until it is done. By contrast, when we hit the Bitmap Draw button, drawing doesn't start immediately. This method actually draws on an in-memory Bitmap object, and when all drawing is done, it displays the bitmap.

Book.jpg