Previous | Next | Trail Map | Creating a User Interface | Working with Graphics


Eliminating Flashing: Implementing Double Buffering

The previous page showed you how to eliminate flashing by implementing the update() method. You might have noticed (depending on the performance of your computer) that the resulting applet, although it didn't flash, appeared to crawl a bit. That is, instead of the whole drawing area (or frame) being updated at once, sometimes one part would be updated before the part just to its right, causing noticeably uneven drawing between sections.

You can use double buffering to avoid this crawling effect by forcing the entire frame to be drawn at once.

Here is the code for the graphics animation example, modified so that it implements double buffering. Below is the resulting applet in action.


Your browser can't run 1.0 Java applets. Here is a snapshot of what you'd see:


To create an offscreen buffer with the AWT, you need to first create an image of the proper size and then get a graphics context to manipulate the image. Below is the code that does this:

/* Where instance variables are declared: */
Dimension offDimension;
Image offImage;
Graphics offGraphics;
. . .
/* In the update() method, where d holds the size of the drawing area: */
if ( (offGraphics == null)
  || (d.width != offDimension.width)
  || (d.height != offDimension.height) ) {
    offDimension = d;
    offImage = createImage(d.width, d.height);
    offGraphics = offImage.getGraphics();
}
Below, in bold font, is the new drawing code in the update() method. Note that the drawing code now clears the entire background, but that it doesn't cause flashing because the code is drawing to the offscreen buffer, not to the screen. Note also that all the calls to fillRect() are performed to the offscreen buffer. The final result is drawn to the screen just before the update() method returns.
public void update(Graphics g) {
    . . . // First, initialize variables and create the
          // offscreen buffer as shown above. Then: 
    // Erase the previous image.
    offGraphics.setColor(getBackground());
    offGraphics.fillRect(0, 0, d.width, d.height);
    offGraphics.setColor(Color.black);

    . . . // Do everything the old paint() method did --
          // until we draw the rectangle.
    // Draw the rectangle if necessary.
    if (fillSquare) {
        offGraphics.fillRect(x, y, w, h);
        fillSquare = false;
    } else {
        fillSquare = true;
    }

    . . . // The rest is exactly like the old paint() method
          // until the very end, when we add the following:
    // Paint the image onto the screen.
    g.drawImage(offImage, 0, 0, this);
}
You might wonder why the offscreen image and graphics context are created in the update() method, instead of in (for example) the start() method. The reason is that the image and graphics context depend on the size of the applet Panel's drawing area, and the size of any Component's drawing area is not valid until the Component is just about to be drawn to the screen for the first time.


Previous | Next | Trail Map | Creating a User Interface | Working with Graphics