ShipSimulation.java Illustrates the basic approach of multithreaded graphics whereas a thread adjusts parameters affecting the appearance of the graphics and then calls repaint to schedule an update of the display.
import java.applet.Applet; import java.awt.*; public class ShipSimulation extends Applet implements Runnable { ... public void run() { Ship s; for(int i=0; i * When the "stop" button is pressed, stop the thread and * clear the Vector of circles. */ public void actionPerformed(ActionEvent event) { if (event.getSource() == startButton) { if (circles.size() == 0) { // Erase any circles from previous run. getGraphics().clearRect(0, 0, getSize().width, getSize().height); animationThread = new Thread(this); animationThread.start(); } int radius = 25; int x = radius + randomInt(width - 2 * radius); int y = radius + randomInt(height - 2 * radius); int deltaX = 1 + randomInt(10); int deltaY = 1 + randomInt(10); circles.addElement(new MovingCircle(x, y, radius, deltaX, deltaY)); } else if (event.getSource() == stopButton) { if (animationThread != null) { animationThread = null; circles.removeAllElements(); } } repaint(); } /** Each time around the loop, call paint and then take a * short pause. The paint method will move the circles and * draw them. */ public void run() { Thread myThread = Thread.currentThread(); // Really while animationThread not null while(animationThread==myThread) { repaint(); pause(100); } } /** Skip the usual screen-clearing step of update so that * there is no flicker between each drawing step. */ public void update(Graphics g) { paint(g); } /** Erase each circle's old position, move it, then draw it * in new location. */ public void paint(Graphics g) { MovingCircle circle; for(int i=0; i windowWidth) && (deltaX > 0)) { setDeltaX(-deltaX); } if ((y -radius < 0) && (deltaY < 0)) { setDeltaY(-deltaY); } else if((y + radius > windowHeight) && (deltaY > 0)) { setDeltaY(-deltaY); } } public int getDeltaX() { return(deltaX); } public void setDeltaX(int deltaX) { this.deltaX = deltaX; } public int getDeltaY() { return(deltaY); } public void setDeltaY(int deltaY) { this.deltaY = deltaY; } } *// SimpleCircle.java A class to store the x, y, and radius of a circle. Also, provides a draw method to paint the circle on the graphics object. import java.awt.*; /** A class to store an x, y, and radius, plus a draw method. * */ public class SimpleCircle { private int x, y, radius; public SimpleCircle(int x, int y, int radius) { setX(x); setY(y); setRadius(radius); } /** Given a Graphics, draw the SimpleCircle * centered around its current position. */ public void draw(Graphics g) { g.fillOval(x - radius, y - radius, radius * 2, radius * 2); } public int getX() { return(x); } public void setX(int x) { this.x = x; } public int getY() { return(y); } public void setY(int y) { this.y = y; } public int getRadius() { return(radius); } public void setRadius(int radius) { this.radius = radius; } } *// DoubleBufferBounce.java An enhancement to the previous applet containing bouncing circles. In this case, double buffering is used to improve the animation; all incremental updating is done in an off-screen image and then the image is drawn to the screen. import java.applet.Applet; import java.awt.*; import java.awt.event.*; import java.util.Vector; /** Bounce circles around on the screen, using double buffering * for speed and to avoid problems with overlapping circles. * Overrides update to avoid flicker problems. * */ public class DoubleBufferBounce extends Applet implements Runnable, ActionListener { private Vector circles; private int width, height; private Image offScreenImage; private Graphics offScreenGraphics; private Button startButton, stopButton; private Thread animationThread = null; public void init() { setBackground(Color.white); width = getSize().width; height = getSize().height; offScreenImage = createImage(width, height); offScreenGraphics = offScreenImage.getGraphics(); // Automatic in some systems, not in others. offScreenGraphics.setColor(Color.black); circles = new Vector(); startButton = new Button("Start a circle"); startButton.addActionListener(this); add(startButton); stopButton = new Button("Stop all circles"); stopButton.addActionListener(this); add(stopButton); } /** When the "start" button is pressed, start the animation * thread if it is not already started. Either way, add a * circle to the Vector of circles that are being bounced. * * When the "stop" button is pressed, stop the thread and * clear the Vector of circles. */ public void actionPerformed(ActionEvent event) { if (event.getSource() == startButton) { if (circles.size() == 0) { animationThread = new Thread(this); animationThread.start(); } int radius = 25; int x = radius + randomInt(width - 2 * radius); int y = radius + randomInt(height - 2 * radius); int deltaX = 1 + randomInt(10); int deltaY = 1 + randomInt(10); circles.addElement(new MovingCircle(x, y, radius, deltaX, deltaY)); repaint(); } else if (event.getSource() == stopButton) { if (animationThread != null) { animationThread = null; circles.removeAllElements(); } } } /** Each time around the loop, move each circle based on its * current position and deltaX/deltaY values. These values * reverse when the circles reach the edge of the window. */ public void run() { MovingCircle circle; Thread myThread = Thread.currentThread(); // Really while animationThread not null. while(animationThread==myThread) { for(int j=0; j= NUMIMAGES) { index = 0; } parent.repaint(); try { Thread.sleep(100); } catch (InterruptedException e) { break; // Break while loop. } } } } *// TimedAnimation.java An applet that demonstrates animation of an image by using a Timer. Note that Timer is located in the javax.swing package. import java.awt.*; import javax.swing.*; /** An example of performing animation through Swing timers. * Two timed Dukes are created with different timer periods. * */ public class TimedAnimation extends JApplet { private static final int NUMDUKES = 2; private TimedDuke[] dukes; private int i, index; public void init() { dukes = new TimedDuke[NUMDUKES]; setBackground(Color.white); dukes[0] = new TimedDuke( 1, 100, this); dukes[1] = new TimedDuke(-1, 500, this); } // Start each Duke timer. public void start() { for (int i=0; i= NUMIMAGES) { index = 0; } parent.repaint(); } // Public service to start the timer. public void startTimer() { timer.start(); } // Public service to stop the timer. public void stopTimer() { timer.stop(); } } **//