您的位置:首页 > 其它

Flicker Free Graphics

2004-11-11 11:12 330 查看
by Eric Giguere
Release 1.0
July 25, 2001

The Mobile Information Device Profile (MIDP) defines low-level user interface classes for drawing directly on a device's display. The Using the MIDP Low-Level User Interface API tip covered how to use these classes to do basic drawing. This tip builds on that foundation and discusses how to use double buffering to draw flicker-free graphics.

The term "double buffering" refers to a common technique used in computer graphics. If you consider a device's display to be a memory buffer into which drawing primitives write (the drawing primitives are the basic drawing methods such as
drawLine
and
drawArc
), with double buffering you draw into a second, offscreen memory buffer and then copy the entire contents of the second buffer into the display buffer. Copying from one buffer to another is a very fast operation on most devices, so that the display changes almost instantaneously. By comparison, directly drawing to a display sometimes causes users to see a flicker, as individual parts of the display are updated. Double buffering avoids this flickering by combining multiple individual drawing operations (that is, those to the offscreen buffer) into a single copy operation to the display buffer.

It's easy to do double buffering in the context of the Mobile Information Device Profile. You can use the
Image
class (all classes mentioned in this tip are in the
javax.microedition.lcdui
package) to create an offscreen memory buffer. You use the
Graphics
class, the same class used to draw on the display, to draw to the offscreen buffer. You also use the
Graphics
class to copy the contents of the offscreen buffer onto the display. Double buffering is implemented with just a few adjustments to your painting routines.

The first thing you need to do is determine if double buffering is even necessary. On some implementations, double buffering is automatically supported by the system. In other words, when the system calls your
Canvas
object's
paint
method, the
Graphics
object passed to the method is that of an offscreen buffer managed by the system; the object is not from the display buffer. The system then takes care of copying the offscreen buffer to the display. Checking if double buffering is supported is easy -- all you do is call the
isDoubleBuffered
method, like this:

public class MyCanvas extends Canvas {

private Image offscreen = null;
private int   height;
private int   width;

public MyCanvas(){
height = getHeight();
width = getWidth();

if( !isDoubleBuffered() ){
offscreen = Image.createImage( width, height );
}

..... // other initialization as appropriate
}

...... // other code, including paint method
}
Notice how if
isDoubleBuffered
returns false, the constructor creates an offscreen buffer of the same width and height as the
canvas
. If the display is double buffered,
isDoubleBuffered
returns true and the offscreen buffer is not created.

The offscreen buffer is created by calling one of the
Image.createImage
methods. There are four such methods, each of which does the following:

Loads images from the MIDlet suite's JAR file
Makes a copy of an existing image
Creates an image from raw binary data
Creates a blank image of a specific height and width

The last of these
createImage
methods is the one used for double buffering. The other three
createImage
methods cannot be used for double buffering because they create images that are immutable, that is, images that cannot be changed. Only the last
createImage
method, the one that takes width and height parameters, can be used to create mutable images. Once you have a mutable image, you can call its
getGraphics
method to obtain a
Graphics
object that you can use to draw into the image's buffer, just like drawing on the display.

Of course, the real work occurs in the
paint
method. A simple paint routine might look like this:

protected void paint( Graphics g ){
g.setColor( 255, 255, 255 );
g.fillRect( 0, 0, width, height );
}
Most
paint
routines are much more complicated, especially if animation is involved. To implement double buffering, add a few lines of code before and after the existing painting code, like this:

protected void paint( Graphics g ){
Graphics saved = g;

if( offscreen != null ){
g = offscreen.getGraphics();
}

g.setColor( 255, 255, 255 );
g.fillRect( 0, 0, width, height );

if( g != saved ){
saved.drawImage( offscreen, 0, 0,
Graphics.LEFT | Graphics.TOP );
}
}
Basically all you're doing is obtaining the
Graphics
object for the offscreen buffer and using it to do the painting. At the end, the entire content of the offscreen buffer is copied to the display. Notice that this is done only if double buffering is not automatically supported. You can easily determine this by checking to see if an offscreen buffer has been allocated. If double buffering is automatically supported, you simply draw directly onto the display as usual.

Double buffering is not without its price. If you're only making small changes to the display, it might be slower to use double buffering. In addition, image copying isn't very fast on some systems; on those systems flicker can can happen even with double buffering. And there is a memory penalty to pay for double buffering: the offscreen memory buffer can consume a large amount of memory, memory that you might not be able to spare. Keep the number of offscreen buffers to a minimum. You could free the offscreen buffer whenever the
canvas
is hidden, for example, and allocate it again when the
canvas
is shown again. This is easy to do by overriding the
canvas
'
hideNotify
and
showNotify
methods.


About the Author: Eric Giguere is a software developer for iAnywhere Solutions, a subsidiary of Sybase, where he works on Java technologies for handheld and wireless computing. He holds BMath and MMath degrees in Computer Science from the University of Waterloo and has written extensively on computing topics.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: