/** Copyright (c) 1995, 1996 Sun Microsystems, Inc. All Rights Reserved.
  ** Extends Arthur van Hoff's animation template, to create an animation
  ** by loading, displaying, and moving a sequence of images in gif format.
  ** In addition to double buffering, MediaTracker is used to load all the
  ** images before starting the animation.
  **
  ** Modified to AnimatorApplet5 by John Pais, March 1998.              **/
 
Toggle your browser's Back and Forward buttons to compare the running applet to this code.
Click here to run a fresh copy of the applet:  AnimatorApplet5.html
 
/** USE EXISTING JAVA CLASSES **/

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

/** EXTEND THE JAVA APPLET CLASS AND IMPLEMENT THE RUNNABLE INTERFACE **/

public class AnimatorApplet5 extends Applet implements Runnable
  {int frameNumber = -1;
    int delay;
    Thread animatorThread;
    boolean frozen = false;
    Font font=new Font("TimesRoman",Font.BOLD,24);
    FontMetrics fontm = getFontMetrics(font);
    String framestr = "";
    Dimension preImageDim;               // Define preImage variables needed to
    Image preImage;                            // create the offscreen copy of the image
    Graphics preImageGraphics;          // we want to paint on the screen.

    Image gifImage[];                          // Define an array of gif images and
    MediaTracker tracker;                  // a tracker to preload them.
    int HiNumber;
 
Toggle your browser's Back and Forward buttons to compare the running applet to this code.
Click here to run a fresh copy of the applet:  AnimatorApplet5.html
 
     /** INITIALIZE THE APPLET **/

    public void init()
      {setBackground(Color.magenta);
        String str;
        int fps = 10;                             // Define the default fps (frames per second).
        str = getParameter("fps");         // Possibly, get HTML string specifying the
        try                                           // fps.
         {if (str != null)
           {fps = Integer.parseInt(str);}  // If possible, convert HTML fps to an
          }                                            // integer.
        catch (Exception e) {}              // In case the try caused something strange.
        delay = (fps > 0) ? (1000/fps): 100; // Convert fps to the milisecond delay
                                                               // time between frames.
        gifImage = new Image[10];
        tracker = new MediaTracker(this);  // Spawn the tracker background thread(s)
        for (int i = 1; i <= 10; i++)               // in order to preload the images.
         {gifImage[i-1] = getImage(getCodeBase(),
                            "images/T"+i+".gif");
          tracker.addImage(gifImage[i-1],0);
          }
       }
 
Toggle your browser's Back and Forward buttons to compare the running applet to this code.
Click here to run a fresh copy of the applet:  AnimatorApplet5.html
 
    /** CLICK TO START OR STOP THE APPLET **/
 
    public boolean mouseDown(Event e, int x, int y)
       {if (frozen)
         {frozen = false;
           start();}
         else
          {frozen = true;
            animatorThread = null;                // Instead of calling stop() here, since
            }                                                // stop() now nullifies our preImage context,
         return true;                                     // nullify only the animation thread in case
         }                                                   // we want to build on our current preImage.
 
    /** GENERATE AND/OR START THE ANIMATION THREAD **/
 
    public void start()
       {if (frozen) { }                                           // The animation is supposed to stay frozen.
         else                                                         // Otherwise, generate and/or start the
          {if (animatorThread == null)                    // animation thread. Apparently, if run
            {animatorThread = new Thread(this);}  // breaks after catching an exception,
            animatorThread.start();                          // the animatorThread though not null
             }                                                          // will still need to be restarted.
         }
 
Toggle your browser's Back and Forward buttons to compare the running applet to this code.
Click here to run a fresh copy of the applet:  AnimatorApplet5.html
 
    /** CREATE AND DISPLAY FRAMES OF THE ANIMATION THREAD **/

    public void run()
     {try                                                                               // Start loading the images and
       {tracker.waitForAll();}                                                // wait until done before starting
        catch (InterruptedException e) {}                               // the animation.
        Thread.currentThread().setPriority(Thread.MIN_PRIORITY); // Set the priority low.
        long startTime = System.currentTimeMillis();                             // Remember start time.
        while (Thread.currentThread() == animatorThread)                   // The animation loop.
           {frameNumber++;                                                   // Advance the frame number.
            repaint();                                                                // Display the frame.
            try                                                                          // Sleep for the delay period.
             {startTime += delay;
              Thread.sleep(Math.max(0,
                                    startTime-System.currentTimeMillis()));
              }
            catch (InterruptedException e) {break;}                 // In case the try caused
            }                                                                           // something strange, exit
        }                                                                               // the while loop.
 
Toggle your browser's Back and Forward buttons to compare the running applet to this code.
Click here to run a fresh copy of the applet:  AnimatorApplet5.html
 
    /** CREATE THE CURRENT FRAME OF THE ANIMATION THREAD **/
 
    public void paint(Graphics g)          // This technique of painting by calling
     {if (!frozen) update(g);}                 // update, prevents the default (and hidden)
                                                          // behavior of update, and instead allows
    public void update(Graphics g)       // the creation of an offscreen preImage
     {Dimension d = size();                  // preImage before painting the screen.
       if (!tracker.checkAll())                                   // If the images aren't all
        {g.clearRect(0, 0, d.width, d.height);             // loaded, then clear the
          g.drawString("Please wait...",                      // background and notify
                               (d.width-20)/2, d.height/2);    // the user to wait.
         }
       else
        {if ((preImageGraphics == null) ||                  // When all images are loaded,
              (d.width != preImageDim.width) ||          // compare the current applet
              (d.height != preImageDim.height))          // viewing size to our preImage,
          {preImageDim = d;                                    // and if different, resize our
            preImage = createImage(d.width,d.height);  // next preImage.
            preImageGraphics = preImage.getGraphics();
            } 
         preImageGraphics.setColor(getBackground());      // Clear the previous preImage
         preImageGraphics.fillRect(0,0,d.width,d.height);    // by filling with the current
         preImageGraphics.setFont(font);                           // background color (magenta),
         preImageGraphics.setColor(Color.black);             // and then create the next
                                                                                     // offscreen preImage.
         if ((frameNumber + 5) % 10 == 0) HiNumber++;                // Say "Hi" to user,
         framestr = "Hi StLCOP for the " + HiNumber + "th time !";  // and count times.
         int scrollDistance = d.width;                                         // Compute scroll position
         int scrollPosition = frameNumber % scrollDistance;      // of leftmost character
         preImageGraphics.drawString(                                    // of framestr, and draw
              framestr,scrollPosition,d.height/2);                          // framestr above current
         preImageGraphics.drawImage(                                   // image.
              gifImage[frameNumber % 10],                              // Compute current image,
              scrollPosition + (fontm.stringWidth(framestr))/3,    // and draw below framestr.
              d.height/2,this);
                                                                                   // Offscreen preImage completed.
         g.drawImage(preImage,0,0,this);                         // Paint preImage on the screen.
         }
      }
 
Toggle your browser's Back and Forward buttons to compare the running applet to this code.
Click here to run a fresh copy of the applet:  AnimatorApplet5.html
 
    /** STOP THE ANIMATION THREAD **/

    public void stop()
     {animatorThread = null;        // The user either clicked to stop or left the page,
       preImageGraphics = null;    // so wipe out the current thread and preImage context.
       preImage = null;
       }
    }