/** Copyright (c) 1995, 1996 Sun Microsystems, Inc. All Rights Reserved.
  ** Extends Arthur van Hoff's animation template, to create an animated
  ** version of SimpleApplet5, like AnimatorApplet2, but this time using
  ** double buffering to eliminate image flashing and/or crawling.
  **
  ** Modified to AnimatorApplet3 by John Pais, January 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:  AnimatorApplet3.html

/** USE EXISTING JAVA CLASSES **/

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

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

public class AnimatorApplet3 extends Applet implements Runnable
   {int frameNumber = -1;                 // Define and/or initialize some
    int delay;                                      // AnimatorApplet3 class variables.
    Thread animatorThread;
    boolean frozen = true;
    Font font=new Font("TimesRoman",Font.BOLD,24);
    String framestr = "";
    int rval, gval, bval;                        // Define red, green, blue color variables.
    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.
 
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:  AnimatorApplet3.html
 
    /** INITIALIZE THE APPLET **/

    public void init()
       {String str;
        int fps = 1;                               // 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.

    /** 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.
 
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:  AnimatorApplet3.html

    /** 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.
        }

    /** CREATE AND DISPLAY FRAMES OF THE ANIMATION THREAD **/

    public void run()
       {setBackground(Color.white);
        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.
            framestr = "Frame " + frameNumber;                          // Create the frame string.
            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:  AnimatorApplet3.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 ((preImageGraphics == null) ||
          (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 (white),
       preImageGraphics.setColor(Color.blue);               // and then create the next
       preImageGraphics.drawString(framestr,155,27);   // offscreen preImage.
 
       for (int j = 40; j < (size().height - 25); j += 30)       // Set up vertical spacing.
        {for (int i = 5; i < (size().width - 25); i += 30)       // Set up horizontal spacing.
          {rval =(int) Math.floor(Math.random()*256);     // Generate a random color
           gval =(int) Math.floor(Math.random()*256);     // red, green, blue mix.
           bval =(int) Math.floor(Math.random()*256);     // Note the "casting" here.
           preImageGraphics.setColor(new Color(rval,gval,bval));  // Draw a small box with
           preImageGraphics.fillRect(i,j,25,25);                 // the current random color.
           preImageGraphics.setColor(Color.black);         // Draw a black border around
           preImageGraphics.drawRect(i-1,j-1,26,26);       // the edge of the small box.
           }
         }                                                             // 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:  AnimatorApplet3.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;
       }
    }