BohrAnim Applet Source Code
//BohrAnim -- A controllable animation by David L. Zellmer, June 27, 2000
//on 6/27/2000, after much reading, some solutions will be attempted using
//threadname.suspend() and threadname.resume()
//It Works! But I've read somewhere that use of these methods can lead to problems
//and other ways should be found to make threads come and go "naturally."
Begin
import Java classes needed for applet
import java.awt.*; //just load the whole Abstract Window Toolkit (awt) class this time
Declare a new BohrAnim class
extension of the Applet class
declare Runnable interface for threads.
Runnable contains the run() method
this class uses run() to control a thread.
//Set up the animation to use Threads by adding implements Runnable
//Use of threads allows the applet to run concurrently with other tasks
public class BohrAnim extends java.applet.Applet
implements Runnable {
Declare global variables
image array and image position variables
"currentimage" is image shown
"runner" declared the animation thread.
initial value for animation frame delay
Image bohrpix[] = new Image[9]; //set up an array to hold the images
Image currentimage;
int xpos = 10; //ULHC of the image
int ypos = 10;
Thread runner; //runner is a variable used to control the thread.
//runner is really an object which will be declared an instance
//of the class Thread down in the start() method below that will
//actually start the thread running.
int delay = 500; //frame delay in milliseconds
Declare global variables
declare a Panel for controls
scrollbar and button control variables
"debug" for messages while testing
//add these initial variable declarations for the controls
Panel thePanel; //The panel for the controls
Scrollbar delayScrollbar; //Scrollbar for the frame delay
Button runButton; //define button variables
Button pauseButton;
Button stepButton;
Label delayLabel; //Label variable to display the value of delay.
boolean running = true; //track if runner thread suspended or not.
int nowstep = 0; //used for stepping
boolean debug = false; //turn console printouts on or off. Used for debugging.
init() method
executes first when applet is called
loads the animation frames
initializes scrollbar and buttons
calls start().
public void init() {
//load the names into a string array
String bohrnames[] = {"bohr1.gif" , "bohr2.gif" ,
"bohr3.gif" , "bohr4.gif" , "bohr5.gif" , "bohr6.gif" ,
"bohr7.gif" , "bohr8.gif" , "bohr9.gif" };
//load the images into the image array
for (int i=0; i < bohrpix.length; i++) {
bohrpix[i] = getImage(getCodeBase(), "pix/" + bohrnames[i]);
}
//set up the control panel along the bottom border of the applet window
thePanel = new Panel();
setLayout(new BorderLayout());
add("South", thePanel);
thePanel.setLayout(new GridLayout(1,5,5,5));
//init the scrollbar
//arguments are (orientation, initial value, width of scrollbar,
// minimum, maximum value)
//in the Mac OS the width is fixed, so just enter zero.
delayScrollbar = new Scrollbar(Scrollbar.HORIZONTAL, 500, 0, 0, 2000);
//add the panel components
delayLabel = new Label("Frame Delay 500");
thePanel.add(delayLabel);
thePanel.add(delayScrollbar);
runButton = new Button("Run");
thePanel.add(runButton);
pauseButton = new Button("Pause");
thePanel.add(pauseButton);
stepButton = new Button("Step");
thePanel.add(stepButton);
}
start() method
starts the animation thread
called by init().
not the same as runner.resume
final thread termination done by stop()
//boilerplate statement to start the thread when the applet loads
public void start() {
if (runner == null) {
runner = new Thread(this);
runner.start();
}
}
stop() method
stops the animation thread for good
cleans up when the applet is exited
not the same as runner.suspend
//boilerplate statement to stop the thread when the page is not viewed.
public void stop() {
if (runner != null) {
runner.stop();
runner = null;
}
}
run() method
body of the animation thread.
runs the frame display loop
initially called by start() method.
not the same as runner.resume
paused by runner.suspend
final thread termination done by stop()
//run() is called in start() above and runs the animation thread "runner".
//run() is a property of Runnable
//the loop is paused or resumed by runner.suspend() or runner.resume()
//in the methods called by the buttons.
public void run() {
setBackground(Color.white);
running = true;
while (true) {
for (int i = 0; i < bohrpix.length; i++) {
currentimage = bohrpix[i];
repaint();
pause(delay); //see below for this method definition.
}
}
}
pause(time) method
makes the animation thread "sleep"
time parameter in milliseconds
try/catch finds safe time to sleep
//this pause statment declares the delay between frames
//the try catch statement is more boilerplate.
public void pause(int time) {
try {Thread.sleep(time);}
catch (InterruptedException e) { }
}
paint() method
called indirectly by repaint()
repaint() calls update()
update() calls paint().
declares the Graphics object "g"
g.methods are used to draw the images.
//repaint() used above calls this paint statement to draw the new image
//repaint() takes care of restoring the background
public void paint(Graphics g) {
//draw image at xpos, ypos
if (currentimage != null)
g.drawImage (currentimage, xpos, ypos, this);
}
update() method
overrides screen clearing before a paint()
reduces animation flicker.
//try reducing flicker by overriding update() to not clear the screen between
//frames. I will have to see if everything gets overpainted in the new frame.
//It worked! But I did have to re-save my transparent gifs with a white background.
//Override Update()
public void update(Graphics g) {
paint(g);
}
handleEvent() method
determines if scrollbar is used
gets frame delay time from scrollbar
//add in this event handler. This one handles only the scrollbar.
//I used separate handlers for the buttons. It seems to work OK.
public boolean handleEvent(Event event) {
if (event.target instanceof Scrollbar) {
delay = delayScrollbar.getValue();
delayLabel.setText("Frame Delay " + String.valueOf(delay));
repaint(); //I wonder if this is needed to repaint the scrollbar?
return true;
}
return super.handleEvent(event); //is this needed? It works.
}
action() method
determines if a button has been pressed
calls the handleButtons() method
//this method determines which of the buttons are pressed, then passes
//the information along to the appropriate handler method found below.
//note that the other event handler used for the scrollbar does not pass information
public boolean action(Event evt, Object arg) {
if (evt.target instanceof Button) {
handleButtons((String) arg);
return true;
}
return super.action(evt, arg);
}
handleButtons(name) method
called by action()
determines which button is pressed
calls the appropriate method
//now for the button handler itself. I picked this name.
//in the example of TYJM they did not declare this public
public void handleButtons(String bname) { //bname will be local to this method.
if (bname.equals("Run")) {
delayLabel.setText("Frame Delay " + String.valueOf(delay));
if (debug) System.out.println("Run has been pressed.");
runanim(); //6/27/2000 call runanim()
}
else if (bname.equals("Pause")) {
//this suspends the running animation.
if (debug) System.out.println("Pause has been pressed.");
pauseanim();
}
else if (bname.equals("Step")) {
//stops the running animatio
if (debug) System.out.println("Step has been pressed.");
stepanim();
}
repaint(); //just put this in as act of desperation.
}
//the following are the new methods that execute with each button
runanim() method
press "Run" button to execute
called by handleButtons()
makes the animation loop indefinitely
public void runanim() {
if (debug) System.out.println("In runanim.");
delayLabel.setText("Frame Delay " + String.valueOf(delay));
if (!running) {
runner.resume();
if (debug) System.out.println("Runner resumed.");
running = true;
}
repaint();
}
stepanim() method
press "Step" button to execute
called by handleButtons()
steps animation one frame
public void stepanim() {
if (debug) System.out.println("In stepanim.");
if (running) {
runner.suspend();
if (debug) System.out.println("Runner suspended.");
running = false;
}
if (nowstep >= bohrpix.length) nowstep = 0;
currentimage = bohrpix[nowstep];
if (debug) System.out.println("nowstep = " + nowstep);
nowstep = nowstep + 1;
repaint();
}
pauseanim() method
press "Pause" button to execute
called by handleButtons()
stops animation at current frame
public void pauseanim() {
if (debug) System.out.println("In pauseanim.");
if (running) {
runner.suspend(); //suspend runner thread.
if (debug) System.out.println("Runner suspended.");
running = false;
}
delayLabel.setText("Frame Delay " + String.valueOf(delay));
if (debug) System.out.println("Pause button pressed.");
}
}
This is the end of the applet.