Java Application Double Buffering

Share it!

What is double buffering and why would anyone be interested in it? Double buffering is used to prevent flicker in animation and games. Although there are many examples of how to do this on the web, most of it is geared towards java applets. Here we focus on java applications. Second, double buffering is a simple concept, but one has to remember to do number of things that are not intuitive before it works properly.

Double buffering works like this: while the user is viewing the current frame, we draw on the next frame in memory until it is completely finished. Then we copy the whole frame into display device in one shot. While the user is viewing that frame, we start drawing on the next frame until it is completely finished, and copy that frame to the display device. The cycle repeats as long as the user is viewing the animation/game.

To run the sample program provided below, DOWNLOAD it and compile it by typing javac and then run it by typing java DoubleBuffering. You will first see an empty red window, after you click anywhere on the screen a small blue rectangle will appear. After that whenever you click on the screen, the X co-ordinate of the previous click will be displayed on the screen. Not exciting at all! But it shows the image is created in memory until the next click, and it is copied onto the display device.

	 bi = (BufferedImage) g.createImage(400, 300);
	 if (bi == null) {
	     System.out.println("Null pointer");
	 Graphics big = bi.createGraphics();
	 big.drawRect(20, 40, 100, 100);
	 big.fillRect(20, 40, 100, 100);

The code snippet above shows the first thing to remember when we create a BufferedImage. It must be done after the window becomes visible. You may be tempted to create an image in memory, set it up, and then display it with setVisible, but this idea does not work. BufferedImage can only be created from a visible window.

In fact, even if you call createImage right after setVisible(), it is possible that setVisible() will return before the window is completely created. In that case a null pointer will be returned from createImage(). This can be fixed with a call to sleep(0) just before createImage() to let the other thread finish realizing the window. Probably depends on the JVM that is running the program.

Next we create a Graphics context for the BufferedImage (only once) and start drawing on it. None of the statements after setVisible() effects the current visible window. You can see that we already draw a blue rectangle on it, but the user will not see it, until we click anywhere on the screen.

    public static void handleMouseClicked(Point s) {
	Graphics gr = g.getGraphics();
	gr.drawImage(bi, 0, 0, null);
	gr = bi.getGraphics();
	gr.fillRect(0, 0, 400, 300);
	gr.drawString(Integer.toString(s.x), 200, 50);

The code snippet above shows what happens when we click anywhere on the screen. We do getGraphics() on the display device and draw BufferedImage object on it. While the user is viewing it, we start drawing on the BufferedImage object again.

This all works fine, but when you start adding Panels or other components to the Frame, it will not work. You have to remember to call .validate() any time you add a component to the Frame.

To create a simple game, we can create two BufferedImage’s: one to keep the background, and the other as a working buffer. To create each frame, first we copy the background to the working buffer, and paint each object over it. Then we copy the working buffer into the display device in one shot. Note that depending on the size of the BufferedImage, it may take a while to copy the whole buffer.

Share it!

This entry was posted in Projects and tagged , . Bookmark the permalink.

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">