×
Namespaces

Variants
Actions
Revision as of 06:41, 16 July 2012 by hamishwillee (Talk | contribs)

Using double buffering in Java ME

From Nokia Developer Wiki
Jump to: navigation, search
Article Metadata
Code ExampleTested with
Devices(s): Nokia 6131, Nokia E70
CompatibilityArticle
Keywords: javax.microedition.lcdui.Image.createImage, javax.microedition.lcdui.Canvas.isDoubleBuffered
Created: vltsoy (27 Nov 2008)
Last edited: hamishwillee (16 Jul 2012)

Contents

Overview

This code snippet demonstrates how to implement double buffering within a MIDlet.

To avoid flickering when drawing animation, the application can draw the image on an off-screen buffer, and then copy its contents to the screen when the drawing operations are finished.

Method isDoubleBuffered checks if the Canvas is double buffered by the implementation.

Source file: DoubleBuffering.java

import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.midlet.MIDlet;
 
 
public class DoubleBuffering extends MIDlet implements CommandListener {
 
private ExtendedCanvas canvas;
private Display display;
private Command exitCommand;
 
/**
* Constructor. Constructs the object and initializes displayables.
*/

public DoubleBuffering() {
// Create canvas with double buffering.
canvas = new ExtendedCanvas();
 
exitCommand = new Command("Exit", Command.EXIT, 1);
canvas.addCommand(exitCommand);
canvas.setCommandListener(this);
display = Display.getDisplay(this);
display.setCurrent(canvas);
}
/**
* From CommandListener.
* Called by the system to indicate that a command has been invoked on a
* particular displayable.
* @param cmd the command that was invoked
* @param displayable the displayable where the command was invoked
*/

public void commandAction(Command cmd, Displayable displayable) {
if (cmd == exitCommand) {
notifyDestroyed();
}
}
 
 
/**
* From MIDlet.
* Called when the MIDlet is started.
*/

public void startApp() {
// No implementation required.
}
 
/**
* From MIDlet.
* Called to signal the MIDlet to enter the Paused state.
*/

public void pauseApp() {
// No implementation required.
}
 
/**
* From MIDlet.
* Called to signal the MIDlet to terminate.
* @param unconditional whether the MIDlet has to be unconditionally
* terminated
*/

public void destroyApp(boolean unconditional) {
}
}

Source file: ExtendedCanvas.java

import java.util.Timer;
import java.util.TimerTask;
import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
 
public class ExtendedCanvas extends Canvas {
 
private Image buffer = null;
//Buffer height and width
private int height;
private int width;
 
//Animation object position.
private int xPos;
private int yPos;
 
//Animation object movement speed.
private int xSpeed = 3;
private int ySpeed = 3;
 
//Timer for animation.
private Timer timer;
private TimerTask timerTask;
 
/**
* Constructor. Constructs the object and initializes buffer.
*/

public ExtendedCanvas() {
height = getHeight();
width = getWidth();
//Get screen center coordinates.
xPos = width/2;
yPos = height/2;
//If double buffering not implemented already
if (!isDoubleBuffered()) {
//Create buffer.
buffer = Image.createImage(width, height);
}
 
//Scheduling new task, which will call
// canvas redraw every 10 miliseconds.
timer = new Timer();
timerTask = new AnimationTimerTask(this);
timer.schedule(timerTask, 0, 10);
}
 
/**
* From Canvas.
* Called by the system to redraw canvas.
* @param graphics used for drawing operations.
*/

protected void paint(Graphics graphics) {
Graphics savedGraphics = graphics;
if (buffer != null) {
graphics = buffer.getGraphics();
}
// Clear canvas.
graphics.setColor(255, 255, 255);
graphics.fillRect(0, 0, width, height);
 
graphics.setColor(255, 0, 0);
// Draw rectangle.
drawAnimation(graphics);
 
if (buffer != null) {
//Copy the ready image to the display memory.
savedGraphics.drawImage(buffer, 0, 0, Graphics.LEFT | Graphics.TOP);
}
 
}
 
/**
* Called to determine next location of the rectangle
* and draw it.
* @param graphics used for drawing operations.
*/

private void drawAnimation(Graphics graphics) {
//Calculate rectangle new position.
xPos += xSpeed;
yPos += ySpeed;
 
//If it crossed borders - change movement direction.
xSpeed = -xSpeed;
if (xPos > width-10 ) {
xPos = width - 10;
} else if ( xPos < 10 ) {
xPos = 10;
} else {
xSpeed = -xSpeed;
}
 
ySpeed = -ySpeed;
if (yPos > height-10 ) {
yPos = height - 10;
} else if ( yPos < 10 ) {
yPos = 10;
} else {
ySpeed = -ySpeed;
}
//Draw it.
graphics.fillRect(xPos-10, yPos-10, 20, 20);
}
 
}

Source file: AnimationTimerTask.java

import java.util.TimerTask;
import javax.microedition.lcdui.Canvas;
 
class AnimationTimerTask extends TimerTask {
 
private Canvas canvas;
 
/**
* Constructor. Constructs the object and initializes variable.
*/

public AnimationTimerTask(Canvas canvas) {
this.canvas = canvas;
}
 
/**
* From TimerTask.
* Redraws canvas.
*/

public final void run() {
canvas.repaint();
}
}

Postconditions

The user will see a simple animation of a flying rectangle. All drawing operations will be performed without flickering.

Supplementary material

You can view the source file and executable application in the attached zip archive. the archive is available for download at Media:Using double buffering in J2ME.zip.

114 page views in the last 30 days.
×