Double
Buffering
Not only are images useful
for storing pictures, as we’ve just shown, but you can also use them as
offscreen drawing surfaces. This allows you to render any image, including text
and graphics, to an offscreen buffer that you can display at a later time. The
advantage to doing this is that the image is seen only when it is complete.
Drawing a complicated image could take several milliseconds or more, which can
be seen by the user as flashing or flickering. This flashing is distracting and
causes the user to perceive your rendering as slower than it actually is. Use
of an offscreen image to reduce flicker is called double buffering, because the screen is considered a buffer for
pixels, and the offscreen image is the second buffer, where you can prepare
pixels for display.
Earlier in this chapter, you
saw how to create a blank Image
object. Now you will see how to draw on that image rather than the screen. As
you recall from earlier chapters, you need a Graphics object in order to use any of Java’s rendering methods.
Conveniently, the Graphics object
that you can use to draw on an Image is
available via the getGraphics( ) method.
Here is a code fragment that creates a new image, obtains its graphics context,
and fills the entire image with red pixels:
Canvas c = new Canvas();
Image test = c.createImage(200, 100); Graphics
gc = test.getGraphics(); gc.setColor(Color.red); gc.fillRect(0, 0, 200, 100);
Once you have constructed and
filled an offscreen image, it will still not be visible. To actually display
the image, call drawImage( ). Here
is an example that draws a time-consuming image to demonstrate the difference
that double buffering can make in perceived drawing time:
/*
<applet code=DoubleBuffer width=250
height=250>
</applet>
*/
import java.awt.*; import java.awt.event.*;
import java.applet.*;
public class DoubleBuffer extends Applet { int
gap = 3;
int mx, my;
boolean flicker = true; Image buffer = null;
int w, h;
public void init() { Dimension d = getSize(); w
= d.width;
h = d.height;
buffer = createImage(w, h);
addMouseMotionListener(new MouseMotionAdapter() {
public void mouseDragged(MouseEvent me) { mx =
me.getX();
my = me.getY(); flicker = false; repaint();
}
public void mouseMoved(MouseEvent me) { mx =
me.getX();
my = me.getY(); flicker = true;
repaint();
}
});
}
public void paint(Graphics g) { Graphics
screengc = null;
if (!flicker) { screengc = g;
g = buffer.getGraphics();
}
g.setColor(Color.blue); g.fillRect(0, 0, w, h);
g.setColor(Color.red); for (int i=0; i<w;
i+=gap)
g.drawLine(i, 0, w-i, h); for (int i=0; i<h;
i+=gap)
g.drawLine(0, i, w, h-i);
g.setColor(Color.black);
g.drawString("Press mouse button to double
buffer", 10, h/2);
g.setColor(Color.yellow);
g.fillOval(mx - gap, my - gap, gap*2+1,
gap*2+1);
if (!flicker) { screengc.drawImage(buffer, 0,
0, null);
}
}
public void update(Graphics g) { paint(g);
}
}
This simple applet has a
complicated paint( ) method. It
fills the background with blue and then draws a red moiré pattern on top of
that. It paints some black text on top of
that and then paints a yellow
circle centered at the coordinates mx,
my. The mouseMoved( ) and mouseDragged(
) methods are overridden to track the mouse position. These methods are
identical, except for the setting of the flicker
Boolean variable. mouseMoved( ) sets
flicker to true, and mouseDragged( ) sets
it to false. This has the effect of
calling repaint( ) with flicker set to true when the mouse is moved (but no button is pressed) and set to false when the mouse is dragged with
any button pressed.
When paint( ) gets called with flicker
set to true, we see each drawing
operation as it is executed on the screen. In the case where a mouse button is
pressed and paint( ) is called with flicker set to false, we see quite a different picture. The paint( ) method swaps the Graphics
reference g with the graphics
context that refers to the offscreen canvas, buffer, which we
created in init( ). Then all of the
drawing operations are invisible. At the end of paint( ), we simply call
drawImage( ) to show the results of these drawing methods all at once.
Figure
27-2 Output from DoubleBuffer without (left) and with (right) double
buffering
Notice that it is okay to
pass in a null as the fourth
parameter to drawImage( ). This is
the parameter used to pass an ImageObserver
object that receives notification of image events. Since this is an image that
is not being produced from a network stream, we have no need for notification.
The left snapshot in Figure 27-2 is what the applet looks like with the mouse
button not pressed. As you can see, the image was in the middle of repainting
when this snapshot was taken. The right snapshot shows how, when a mouse button
is pressed, the image is always complete and clean due to double buffering.
Related Topics
Privacy Policy, Terms and Conditions, DMCA Policy and Compliant
Copyright © 2018-2023 BrainKart.com; All Rights Reserved. Developed by Therithal info, Chennai.