jeffheaton's picture
in

In the last two articles you saw that Java provides a number of drawing commands. These drawing commands are all accessed through a "Graphics" object. When you issue a command such as:

g.fillRect(0,0,100,100);

The rectangle is drawn directly onto the screen. Double buffering allows you to obtain a special "Graphics" object that draws to an "Image" object, rather than directly to the screen.

You might be wondering why you would want to draw to an "Image" object, rather than directly to the screen. There are several new options that become available when you can draw directly to an image.

  • You can create your own image
  • You can eliminate flicker

First lets look at why you might want to create your own image. Consider a small image that you might want to draw many times in your program. It might take many drawing commands to produce this image. If you draw this complex image to an Image object, you can simply draw the image each time you want to display your complex drawing. Figure 3.1 shows such a program.

 Repeating a complex drawing

Figure 3.1: Repeating a complex drawing

As you can see from Figure 3.1 a shaded ball is drawn many times. To produce this effect the program draws one single ball to an off-screen "Image" object. Then the program loops over and draws this image across the screen. Listing 3.1 shows how the program accomplishes this.

Listing 3.1: Displaying a red ball using an off-screen image (DoubleApplet.java)

import java.awt.*;
import java.awt.event.*;
import java.applet.*;

public class DoubleApplet extends Applet
{
  /**
   * When this class is ran as an application, how wide should it be.
   */
  public static final int IDEAL_WIDTH = 640;

  /**
   * When this class is ran as an application, how tall should it be.
   */
  public static final int IDEAL_HEIGHT = 480;

  /**
   * This method paints the display.
   *
   * @param g The graphics object to paint to.
   */
  public void paint(Graphics g)
  {
    final int size = 128;

    Image image = createImage(size + 1, size + 1);
    Graphics offG = image.getGraphics();

    offG.setColor(Color.BLACK);
    offG.fillRect(0, 0, getWidth(), getHeight());

    for (int i = 0; i < size; i++)
    {
      int c = i * 5;
      c = Math.min(c, 255);
      offG.setColor(new Color(c, 0, 0));
      offG.fillOval(i, i, size - (i * 2), size - (i * 2));
    }

    g.setColor(Color.BLACK);
    g.fillRect(0, 0, getWidth(), getHeight());

    for (int y = 0; y < getHeight() / size; y++)
    {
      for (int x = 0; x < getWidth() / size; x++)
      {
        g.drawImage(image, x * size, y * size, null);
      }
    }
  }

  /**
   * The main method is called when the class is to be ran
   * as a Java application. This method creates a frame and
   * attaches the applet to the frame.
   *
   * @param args Not used.
   */
  public static void main(String args[])
  {
    DoubleApplet applet = new DoubleApplet();
    Frame frame = new Frame();
    frame.addWindowListener(new WindowAdapter()
    {
      public void windowClosing(WindowEvent e)
      {
        System.exit(0);
      }
    });

    frame.add(applet);
    frame.setSize(IDEAL_WIDTH, IDEAL_HEIGHT);
    frame.show();
    applet.init();
  }

}

All of the action for this program occurs inside of the "paint" method. First an off-screen image is obtained, and a "Graphics" object is obtained for that image.

Image image = createImage(size + 1, size + 1);
Graphics offG = image.getGraphics();

The off-screen image is created by calling "createImage". The desired size of the image must be specified. Next a "Graphics" object is obtained by calling "getGraphics" on the newly created "Image" object.

Now that you have a "Graphics" object for the off-screen image, you can draw directly onto the image. Anything you draw to this image will not be displayed. You will not see the effects of your drawing until your draw this image, using a "drawImage".

This program draws a series of red circles. This produces a neat shaded effect, as seen in Figure 3.1.

Once the image has been draw to the off-screen image, the program can now display this image wherever needed. This is done with the following lines of code.

for (int y = 0; y < getHeight() / size; y++)
{
   for (int x = 0; x < getWidth() / size; x++)
  {
    g.drawImage(image, x * size, y * size, null);
  }
}

As you can see, the above lines of code loop over all of the x and y coordinates and draw a grid of "shaded balls".

This is only the beginning of the uses for off-screen images. Later in this article you will see how you can create an off-screen image that will use to produce smooth animation.


Copyright 2005 - 2012 by Heaton Research, Inc.. Heaton Research™ and Encog™ are trademarks of Heaton Research. Click here for copyright, license and trademark information.