import java.applet.*; import java.awt.*; import javax.swing.*; /* Demo of threads: an Applet that creates a bouncing circle, using a timer thread to update the animation RAB 1/99, inspired by Flanagan, "Java Examples in a Nutshell", 1997 Main idea: We create an Applet Bounce whose paint method draws a red circle at (x,y) and that has a method doStep() for moving the circle by (dx,dy), except reversing direction when the circle reaches a Panel boundary. We also create a separate class TimerThread that calls Bounce.doStep() every N milliseconds. */ public class Bounce extends JApplet implements SteppingProcess { int x = 150, y = 50, r = 50; // position and radius of circle int dx = 11, dy = 7; // physical direction vector components TimerThread timer = new TimerThread(this, 100); public void paint(Graphics g) { g.setColor(getBackground()); g.fillRect(0, 0, getSize().width, getSize().height); g.setColor(Color.red); g.fillOval(x-r, y-r, r*2, r*2); } public void doStep() { // Bounce if we've hit an edge if ((x - r + dx < 0) || (x + r + dx > getSize().width)) dx = -dx; if ((y - r + dy < 0) || (y + r + dy > getSize().height)) dy = -dy; x += dx; y += dy; repaint(); } public void start() { timer.startStepping(); } // override JApplet.start() public void stop() { timer.suspendStepping(); } // override JApplet.stop() } /* SteppingProcess allows Bounce to interact with TimerThread */ interface SteppingProcess { public void doStep(); } /* TimerThread is a separate thread of execution that does nothing but call proc.doStep() periodically */ class TimerThread extends Thread { SteppingProcess proc; // process being timed int delay; // wait in milliseconds between steps private boolean amSuspended = true; // enables/disables the periodic calling of proc.doStep() public TimerThread(SteppingProcess p, int d) { proc = p; delay = d; } public synchronized void startStepping() { amSuspended = false; if (!isAlive()) // assert: run() has not yet been started on this thread start(); else notify(); } public synchronized void suspendStepping() { amSuspended = true; } public void run() { for (;;) { proc.doStep(); try { Thread.sleep(delay); synchronized (this) { while (amSuspended) wait(); } } catch (InterruptedException e) {} } } }