/** Copyright (c) 1995, 1996 Sun Microsystems, Inc. All Rights Reserved.
  ** Extends Arthur van Hoff's animation template, to create an animated
  ** checkerboard, using double buffering to eliminate image flashing
  ** and/or crawling.
  **
  ** Modified to AnimatorApplet4 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:  AnimatorApplet4.html
 
/** USE EXISTING JAVA CLASSES **/
 
import java.awt.*;
import java.applet.Applet;
 
/** EXTEND THE JAVA APPLET CLASS AND IMPLEMENT THE RUNNABLE INTERFACE **/
 
public class AnimatorApplet4 extends Applet implements Runnable
   {int frameNumber = -1;
     int fps = 10;                               // Define the default fps (frames per second)
     int delay;                                    // as a global, in order to initialize in init()
     Thread animatorThread;             // and control the frame-to-frame delay in run().
     int delay;
     Thread animatorThread;
     boolean frozen = true;
     Font font=new Font("TimesRoman",Font.BOLD,24);
     String framestr;
     int squareSize = 20;                       // Define globals for the checkerboard square
     boolean createTopSquareNextFrame = false; // size, and the frame-to-frame top square.
     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.
 
    /** INITIALIZE THE APPLET **/
 
    public void init()
       {setBackground(Color.red);
         String str1, str2;
         int fps = 10;                               // Define the default fps (frames per second).
         str1 = getParameter("fps");         // Possibly, get HTML string specifying the
         try                                             // fps.
         {if (str1 != null)
           {fps = Integer.parseInt(str1);}       // If possible, convert HTML fps to an
           }                                                   // integer.
         catch (Exception e) {}                     // In case the try caused something strange.
         str2 = getParameter("squareSize");   // Possibly, get HTML string specifying
         try                                                   // the squareSize.
         {if (str2 != null)
           {squareSize = Integer.parseInt(str2);} // If possible, convert HTML squareSize
           }                                                        // to an integer.
         catch (Exception e) {}                          // In case the try caused something strange.
          }
 
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:  AnimatorApplet4.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:  AnimatorApplet4.html
 
    /** CREATE AND DISPLAY FRAMES OF THE ANIMATION THREAD **/
 
    public void run()
       {Thread.currentThread().setPriority(Thread.MIN_PRIORITY);  // Set the priority low.
         long startTime = System.currentTimeMillis();                             // Remember start time.
         int delayLong = (fps > 0) ? (10000/fps): 1000;                 // Convert fps to milisecond
         int delayShort = (fps > 0) ? (1000/fps): 100;                    // delay time between frames.
 
         while (Thread.currentThread() == animatorThread)       // The animation loop.
           {frameNumber++;                                                      // Advance the frame number.
             framestr = "Frame " + frameNumber;                        // Create the frame string.
             repaint();                                                                  // Display the frame.
             if (frameNumber != 0)                                              // Start with a longer delay
              {delay = delayShort;}                                              // time for Frame 0, in order
             else                                                                           // to avoid timing problems
              {delay = delayLong;}                                               // when the thread starts up.
             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.
 
    /** 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();                                   // before painting the screen.
       boolean createTopSquare;
       boolean fillSquare;
       int frameShift;
       int squareWidth, squareHeight;
       int x = 0, y = 0;
       int extendRow = 0;

       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 (red),
       preImageGraphics.setColor(Color.black);              // and then create the next
       preImageGraphics.drawString(framestr,155,39);    // offscreen 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:  AnimatorApplet4.html
 
      /* Create the current checkerboard for the current frame. This is done by
          starting with the red background and then moving down the columns of the
          checkerboard (starting with the leftmost column), deciding whether or
          not to paint a black square on top of the red background which creates
          the checkerboard effect. Frame 0 begins by skipping a red square at the
          top of the leftmost column, then paints a black one below it, skips a
          red square below it, paints a black one below it, etc. Frame 1 begins
          its leftmost column with a black square one pixel wide, frame 2 with
          a black square 2 pixels wide, etc. These frames are then displayed in
          sequence, creating the checkerboard moving to the right effect.              */
 
      /* Set up the current frame and remember appropriately for the next frame */
 
      createTopSquare = createTopSquareNextFrame; // Create top square: true/false?
      frameShift = frameNumber % squareSize;             // Compute the frameShift, which is
                                                                                  // a number from 0 to squareSize-1.
       if (frameShift == 0)                                              // frameShift equals the remainder
        {squareWidth = squareSize;                               // after dividing frameNumber by
          createTopSquareNextFrame = !createTopSquare;   // squareSize. So, % is
           }                                                                            // the mod operation.
       else
        {squareWidth = frameShift;                                        // Start the top of the leftmost
          createTopSquareNextFrame = createTopSquare;    // column with a partial square--
           }                                                                            // a rectangle of width frameShift
                                                                                         // (pixels).
 
       fillSquare = createTopSquare;                                    // Fill or don't fill the leftmost
                                                                                         // top (partial) square of the current
                                                                                         // frame, depending on the value of the
                                                                                         // global variable createTopSquare.
 
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:  AnimatorApplet4.html
 
       /* Begin the checkerboard for the current frame */
 
       while (x < d.width)                                         // Begin drawing the first row, but
         {int extendColumn = 0;                                // proceed down each column from top
           while (y < d.height)                                    // to bottom, starting from the left.
             {extendColumn += squareSize;
               if (extendColumn <= d.height)                // Test column extension.
                {squareHeight = squareSize;}
               else                                                        // If a full square won't fit at the
                 {squareHeight = d.height - y;}              // bottom of the column, then reduce
               if (fillSquare)                                           // its height.
                {preImageGraphics.fillRect(x, y, squareWidth, squareHeight);
                  fillSquare = false;
                  }
               else
                {fillSquare = true;}
               y += squareHeight;                              // Increment y.
               }                                                         // End of while y loop.
            x += squareWidth;                                         // Increment x.
            y = 0;                                                             // Start at the top of the next
            extendRow += squareWidth;                          // column.
            if (extendRow <= d.width)                             // Test row extension.
             {squareWidth = squareSize;}
            else                                                                // If a full square won't fit at the
             {squareWidth = d.width - x;}                        // far right, then reduce its width.
            createTopSquare = !createTopSquare;           // Set up to do the opposite at the
            fillSquare = createTopSquare;                         // top of the next column.
            }                                                                    // End of while x loop.
                                                                                  // Offscreen preImage now 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:  AnimatorApplet4.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;
         }
      }