Please send questions to
st10@humboldt.edu .
/**
* TrainWiDblBuf
*
* yet-another Thread demo that is the first using "double buffering"
* to improve animation using threads in an AWT applet.
*
* It uses an AWT Applet and the Runnable interface, also,
* and animates an image of a train moving left to right across
* the applet area.
*
* Expects: train.gif to be in the same directory as its .class file
*
* comments marked with [1] are from Chapter 4, "Graphics", section
* "Animation with Double-Buffering", from Java Examples in a Nutshell, FIRST
* EDITION, Flanagan, O'Reilly, 1997, pp. 64-69
*
* RECOMMENDED SIZE: height 200, width 600
*
* modified by: Sharon M. Tuttle
* last modified: 3-26-01
**/
// A SUMMARY OF SOME IMPORTANT POINTS ABOUT DOUBLE-BUFFERING:
//
// * need a "buffer": that'll be a java.awt.Image object
// * need to create this "buffer" using Component.createImage();
// * this buffer needs a Graphics object to draw to: Image.getGraphics()
// can get the Graphics object for this buffer
// * you draw to the buffer's Graphics object, rather than to the Graphics
// object for the applet;
// * when the drawing of the off-screen image is complete, you copy the off-screen
// image onto the applet screen all at once
// * to prevent applet's default update() method from clearing the screen before
// calling paint() as it does whenever repaint() is called, you
// need to override update() so that it just calls paint()
import java.applet.Applet;
import java.awt.*;
public class TrainWiDblBuf extends Applet implements Runnable
{
int x, y;
Image myTrain;
Thread myRunner;
Image buffer; // [1]"the off-screen image for double-buffering"
Dimension appletSize; // [1]"the size of the applet"
Graphics bufferGraphics; // [1]"a Graphics object for the buffer"
public void init()
{
setBackground(Color.lightGray);
System.out.println("Train with Double Buffering, Version 1.1");
Label yourName = new Label("CIS 480 - Spring 2001");
add(yourName);
Label describe = new Label("Train with Double Buffering: Version 1.1");
add(describe);
// currently in same directory as my .class file
myTrain = getImage(getCodeBase(),"train.gif");
// hard code the y pixel location
y = 100;
// initialize x to 0
x = 0;
//-----
// [1] "set up an off-screen image for double-buffering"
//-----
// get size of applet (appletSize is a Dimension object)
appletSize = this.getSize();
// buffer is now created to be the same size as the applet
buffer = this.createImage(appletSize.width, appletSize.height);
// get a Graphics object for buffer
bufferGraphics = buffer.getGraphics();
}
public void start()
{
if (myRunner == null)
{
// not bothering to name the thread, this time;
myRunner = new Thread(this);
myRunner.start();
}
}
public void run()
{
Thread executingThread;
executingThread = Thread.currentThread();
while (myRunner == executingThread)
{
x = 0;
repaint();
try
{
// sleep for 1 second (1000 msec = 1 sec)
Thread.sleep(1000);
}
catch(InterruptedException e)
{
}
for (int k = 0; k < 120; k++)
{
x = k * 5;
repaint();
try
{
// pause for .1 second between
// repaintings
Thread.sleep(100); // .1 second pause
}
catch (InterruptedException e)
{
}
} //end for
} //end while
}
//suspends execution when user leaves page
public void stop()
{
if (myRunner != null)
{
myRunner = null;
}
}
// VERY IMPORTANT --- [1] "It is important to override this method
// like this for double-buffering" --- this new version of update()
// doesn't clear the screen, it just calls paint() immediately.
public void update(Graphics g)
{
paint(g);
}
// now, when double-buffering, here in paint() I will not paint on
// Graphics object g --- I will paint on my buffer's Graphics object,
// instead
public void paint(Graphics g)
{
bufferGraphics.drawImage(myTrain, x, y, this);
// [1]"then copy the off-screen buffer onto the screen"
// (think: why 0,0 for coordinates, here?)
g.drawImage(buffer, 0, 0, this);
}
}