Click Here!
home account info subscribe login search My ITKnowledge FAQ/help site map contact us


 
Brief Full
 Advanced
      Search
 Search Tips
To access the contents, click the chapter and section titles.

Platinum Edition Using HTML 4, XML, and Java 1.2
(Publisher: Macmillan Computer Publishing)
Author(s): Eric Ladd
ISBN: 078971759x
Publication Date: 11/01/98

Bookmark It

Search this book:
 
Previous Table of Contents Next


Listing 39.16 Animation1.javaThis Applet Loads and Displays a Series of Images in Rapid Succession


 import java.awt.*;
 import java.applet.Applet;

 public class Animation1 extends Applet implements Runnable {
     int fFrame = -1;
     int fDelay;
     Thread fThread;
     Image[] fEarth;

     public void init() {
       fEarth = new Image[30];
       String theString;
       int theFramesPerSecond = 10;

       //load in the images
       for (int i=1; i<=30; i++)
       {
       System.err.println(“Starting load from “ +
          getCodeBase() +
          “ of ./Earth” + i +”.gif”);
           fEarth[i-1] = getImage (getCodeBase(),
                                  “./Earth”+i+”.gif”);
       }

       //How many milliseconds between frames?
       theString = getParameter(“fps”);
       try {
         if (theString != null) {
             theFramesPerSecond = Integer.parseInt(theString );
         }
       } catch (NumberFormatException e) {}
       fDelay = (theFramesPerSecond > 0) ?
                (1000 / theFramesPerSecond) : 100;
     }

     public void start() {
       // start a new thread for the animation
       if (fThread == null) {
           fThread = new Thread(this);
       }
       fThread.start();
     }

     public void stop() {
       // stop the animation thread
       fThread = null;
     }

     public void run() {
       // run at a low priority; animation is second-place to content
       Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
       long theStartTime = System.currentTimeMillis();

       //Here comes the show.
       while (Thread.currentThread() == fThread) {

         //Advance the frame.
         fFrame++;

         //Display it.
         repaint();

         //Delay depending on how far we are behind.
         try {
              theStartTime += fDelay;
              Thread.sleep(Math.max(0,
                                    theStartTime-
                           System.currentTimeMillis()));
         } catch (InterruptedException e) {
                  break;
         }
     }
   }

   //Draw the current frame
   public void paint(Graphics g) {
     g.drawImage(fEarth[fFrame % 30], 0, 0, this);
   }
 }

This applet works, but it suffers from two problems. First, the animation is far from smooth. Even when the images are loading from the local hard drive, we notice a certain jerkiness as the frames change. Second, if we load this applet over the network, the animation may begin before all the image files have finished loading, resulting in an ugly half-drawn frame. In the next two sections we’ll solve both of these problems.

We’re going to use this applet as the basis for building a smooth, flicker-free animation applet. We’ll examine Animation1.java in detail.

You’ll notice that this applet implements an interface called Runnable.Runnable enables the applet to start a new thread of control so the animation can proceed independently of the user interface.


NOTE:  Java interfaces are Sun’s solution to multiple inheritance. A class can only subclass one base class, but it can implement as many interfaces as you like. When you subclass a class (such as Applet), you may override as many or as few of the class’s methods as you like. When you implement an interface, you must provide an implementation for every method in the interface.

Our list of instance variables includes a reference to the animation thread (fThread) and a reference to the array of images. We’re using 30 frames of the revolving Earth, so we call this array fEarth.

In init() we loop from 1 to 30, loading the images of Earth. (They’re stored in files named Earth1.gif through Earth30.gif.)

Next, we look for an applet <PARAM> called fps (frames per second). If we find it, we attempt to parse it into a number. If we don’t find it or if we can’t read it, we use 10 frames per second as the basis for calculating the delay between calls to paint().

When the browser first shows the applet, it calls init() followed by start(). The browser will call stop() if the user iconifies the browser window or moves to a different page. We handle start() by checking to see whether the animation thread has already been set up. If it hasn’t, we instantiate it. In either case, we start() the thread and destroy it in stop().

The required method of Runnable is run(). The Java runtime environment calls this method whenever time is available to run our thread. Our version of run() starts by setting the animation thread’s priority to a low value because any user interaction should take precedence over the animation. Then we simply step through the frames, repaint on each loop, and delay as necessary to match the desired frame rate.

Finally, the work is done in paint() itself (as it is in most graphics-intensive applets). We simply draw the current frame onto the screen.

Loading Images over the Web

As you experiment with this code you’ll discover that it sometimes jerks a bit. This happens when the image doesn’t load fast enough to support the animation, particularly when someone is loading this applet over the Internet.

A simple fix to this problem requires only six lines of code. You add an instance of the MediaTracker class to your applet. The MediaTracker knows which images are already loaded into memory and can prevent you from using an image that has not been fully loaded. A step-by-step procedure for adding a MediaTracker to any animation project follows:

1.  Add a MediaTracker as an instance variable:
MediaTracker fTracker;
2.  In init(), instantiate a new MediaTracker:
fTracker = new c1
MediaTracker( this );
3.  As each image is loaded, place it under the control of the MediaTracker:
fTracker.addImage ( fEarth[i], 0 );

The second parameter to this method, 0, is an ID number that will be used to refer to this set of images.
4.  Before the while loop in run(), call waitForID():
try {
  fTracker.waitForID( 0 );
} catch (InterruptedException e) {
  return;
}
5.  Before using the images in paint(), double-check that they’re loaded:
if (fTracker.checkID( 0 ))


Previous Table of Contents Next


Products |  Contact Us |  About Us |  Privacy  |  Ad Info  |  Home

Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc.
All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.