/*********************************************************************** * Bounce2.java * * This applet is a second pass at controlling a bouncing ball via a * moded start/stop button. * * Comments in the following point out departures from Bounce1.java. ***********************************************************************/ import java.applet.*; import java.awt.*; import java.awt.event.*; public class Bounce2 extends Applet implements ActionListener { private Canvas display = new Canvas(); private Button startStop = new Button("Start"); private Ball ball = null; public void init() { setLayout(new BorderLayout()); add("South", startStop); add("Center", display); startStop.addActionListener(this); } public void actionPerformed(ActionEvent e) { if (e.getActionCommand().equals("Start")) { startStop.setLabel("Stop"); ball = new Ball(display, Color.red); /* We no longer animate the ball here. Instead, we start its * thread. */ ball.start(); } else { startStop.setLabel("Start"); ball.finish(); // Terminate the ball's thread. } } } /*********************************************************************** * class Ball --- This class extends the Thread class, therefore it must * have a run() method. ***********************************************************************/ class Ball extends Thread { private Canvas theCanvas; private Color color; private int x, y; private int dx, dy; private boolean done = false; // Is thead done executing? final static int RADIUS = 5; public Ball(Canvas c, Color co) { theCanvas = c; color = co; x = 0; y = (int) (10 + 480 * Math.random()); dy = (int)(1.0 + Math.round(2.5 * Math.random())); dx = (int)(1.0 + Math.round(2.5 * Math.random())); } /*********************************************************************** * public void run() --- As its last action, the default start() method * calls run(). This is where we use the new thread to animate the * ball. ***********************************************************************/ public void run() { draw(color); while (!done) { move(); /* Try/catch pair necessary as during sleep() the checked * InterruptedException may occur and must be handled. */ try { /* Thread sleeps for 10 ms., yielding control to another * thread. This efficiently replaces our spin-loop. */ sleep(10); } catch (InterruptedException e) { } } draw(Color.white); // Clean up by erasing the ball. } private void draw(Color c) { Graphics g = theCanvas.getGraphics(); g.setColor(c); g.fillOval(x, y, 2*RADIUS, 2*RADIUS); g.dispose(); } private void move() { draw(Color.white); x += dx; y += dy; Dimension d = theCanvas.getSize(); if (x < 0) {x = 0; dx = -dx;} if (x + 2*RADIUS >= d.width) { x = d.width-2*RADIUS; dx = -dx;} if (y < 0) {y = 0; dy = -dy;} if (y + 2*RADIUS >= d.height) { y = d.height-2*RADIUS; dy = -dy;} draw(color); } /*********************************************************************** * public void finish() --- Set the done flag, ultimately causing the * thread to complete. ***********************************************************************/ public void finish() { done = true; } }