Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / GUI / November 2003

Tip: Looking for answers? Try searching our database.

Need some help with animation

Thread view: 
Rhino - 25 Nov 2003 22:00 GMT
I need some help with animation.

Specifically, I am trying to create a class that will play an animated GIF
(GIF89a) in a JPanel and stop or start when the user clicks the mouse. This
seems like something that should be pretty straight forward but I've already
put several hours into this without getting the results I want.

My class *almost* works satisfactorily. The animation starts and stops when
I click (actually, I do two clicks to start it the very first time, after
that the mouse toggles the animation with each click.) Unfortunately, the
animation also disappears whenever it is not running. That's the part I need
help with.

I would like the animated GIF to be visible and initially stopped on the
first frame when it is started the first time, then start when I've clicked
the mouse (twice if it's the very first time since the panel was
instantiated). The animation should stop but leave its current frame visible
when I click the mouse again, then restart from where it left off on the
next click.

I've tried everything I can think of and researched the issue as thoroughly
as I could in Usenet but I can't find an example that does this or any
discussion of the relevant principles so that I can figure it out for
myself.

Here is my code with most of the comments removed so that the post is not
overly long. Please feel free to tell me to do things differently.
Personally, I find the logic in the paintComponent() method a little
odd-looking but I can't think of anything else to try there that hasn't
already failed to work.

package racer;

import java.awt.BorderLayout;

import java.awt.Dimension;

import java.awt.Graphics;

import java.awt.Image;

import java.awt.MediaTracker;

import java.awt.Toolkit;

import java.awt.event.MouseAdapter;

import java.awt.event.MouseEvent;

import java.io.File;

import java.net.URL;

import javax.swing.JFrame;

import javax.swing.JPanel;

public class AnimationPanel extends JPanel implements Runnable {

   final String CLASS_NAME = getClass().getName();

   static final boolean DEBUG = false;

   Thread animationThread = null;

   boolean keepDrawing;

   boolean frozen = false;

   Image animation = null;

   MediaTracker tracker = null;

   int stillWidth = 0;

   int stillHeight = 0;

public static void main(String[] args) {

   JFrame myFrame = new JFrame("Drawing Panel");

   myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

   AnimationPanel drawingPanel = new AnimationPanel("racer/AnimatedGIFs",
"catwalk.gif", true);

   myFrame.getContentPane().add(drawingPanel, BorderLayout.CENTER);

   myFrame.pack();

   myFrame.setVisible(true);

}

public AnimationPanel(String animationImageFilePath, String
animationImageFile, boolean controlWithMouse) {

   super();

/* Get the URL for the animated image file. */

   URL animationGIF =
this.getClass().getClassLoader().getResource(animationImageFilePath +
File.separator + animationImageFile);

/* Get the actual image file. */

   animation = Toolkit.getDefaultToolkit().getImage(animationGIF);

   try {

       tracker = new MediaTracker(this);

       tracker.addImage(animation, 0);

       tracker.waitForAll();

       }

   catch (Exception excp) {

       excp.printStackTrace();

       }

/* Assuming that all of the stills in the animation are the same size,
determine the

height and width of the panel that will be needed to display them. */

   stillWidth = animation.getWidth(this);

   stillHeight = animation.getHeight(this);

/* If the user wishes to control the animation with the mouse, activate this
listener. */

   if (controlWithMouse) {

       addMouseListener(new MouseAdapter() {

           public void mousePressed(MouseEvent evt) {

               if (frozen) {

                   frozen = false;

                   startAnimation();

                   }

               else {

                   frozen = true;

                   stopAnimation();

                   }

               }

           });

       } //end if

} //end AnimationPanel()

public void startAnimation() {

if (animationThread == null) {

   animationThread = new Thread(this);

   keepDrawing = true;

   animationThread.start();

   }

} //end startAnim()

public void stopAnimation() {

if (animationThread != null) {

   keepDrawing = false;

   animationThread = null;

   }

} //end stopAnim()

public void run() {

while (keepDrawing) {

   repaint(); //call paint

   try {

       Thread.sleep(10); //sleep a little to slow it down

       }

   catch (InterruptedException ie_excp) {

       System.err.println("Error: " + ie_excp);

       }

   } //end while

} // end run()

public void paintComponent(Graphics graphics) {

if (!keepDrawing) {

/* If we DON'T paint the parent class (super), other parts of the GUI which
imbed this

* panel overwrite the area where the animation is drawn. If we DO paint the
parent

* class, the animation is blanked out so it disappears when the animation is
stopped

* rather than freezing on the last frame.

*/

       super.paintComponent(graphics);

       return;

       }

   else {

       super.paintComponent(graphics);

       graphics.drawImage(animation, 0, 0, this);

       }

} //end paint()

public Dimension getPreferredSize() {

   return new Dimension(stillWidth, stillHeight);

}

} //end of class

Signature

Rhino
---
rhino1 AT sympatico DOT ca
"If you want the best seat in the house, you'll have to move the cat."

ak - 26 Nov 2003 11:33 GMT
You have some mistakes here.

a) you load only FIRST frame from your GIF, try to use ImageIO to get all of
them
b) use MemoryImageSource to create animation. See javadoc for details.

hope it helps

> I need some help with animation.
>
[quoted text clipped - 258 lines]
> rhino1 AT sympatico DOT ca
> "If you want the best seat in the house, you'll have to move the cat."
Rhino - 26 Nov 2003 13:51 GMT
> You have some mistakes here.
>
> a) you load only FIRST frame from your GIF, try to use ImageIO to get all of
> them

Not really. You are right that I am loading only only file but that file is
an animated GIF (GIF89a) so it contains all the frames.

> b) use MemoryImageSource to create animation. See javadoc for details.

I'll have a look at this.

Thanks!

Rhino

> > I need some help with animation.
> >
[quoted text clipped - 269 lines]
> > rhino1 AT sympatico DOT ca
> > "If you want the best seat in the house, you'll have to move the cat."
ak - 26 Nov 2003 18:54 GMT
> > You have some mistakes here.
> >
[quoted text clipped - 4 lines]
> Not really. You are right that I am loading only only file but that file is
> an animated GIF (GIF89a) so it contains all the frames.

Yes, file contains all frames, but java picks only the first of them.

> > b) use MemoryImageSource to create animation. See javadoc for details.
> >
[quoted text clipped - 283 lines]
> > > rhino1 AT sympatico DOT ca
> > > "If you want the best seat in the house, you'll have to move the cat."
Rhino - 27 Nov 2003 13:32 GMT
> > "ak" <k.andrei@gmx.de.spam> wrote in message
> news:bq2364$12j$1@online.de...
[quoted text clipped - 10 lines]
>
> Yes, file contains all frames, but java picks only the first of them.

Try running my code with any animated GIF of your choice. You'll see that it
is playing all the frames in the file.

> > > b) use MemoryImageSource to create animation. See javadoc for details.
> > >
[quoted text clipped - 289 lines]
> > > > rhino1 AT sympatico DOT ca
> > > > "If you want the best seat in the house, you'll have to move the cat."
zn?rt - 27 Nov 2003 19:29 GMT
>My class *almost* works satisfactorily. The animation starts and stops when
>I click (actually, I do two clicks to start it the very first time, after

Not really. You are not doing the animation, java is. You are just
displaying an animated GIF image. I think you can't achieve your goal
if you don't control the animation yourself.

You would realize this if you fix your paintComponent method, which is
worng, as for what you want. You can't simply "skip" drawing of the
animation when you are not in "keepDrawing" state. That's why yur
animation dissapears, it gets painted over. Instead, you should always
draw the current frame. And in your code you have no idea which this
frame this should be. As "ak" tolds you, you need to have al frames
"separately" in memory.
 
But I'll bet there are view componentss with "pause/resume" behaviours
out there.

regards
znôrt
ak - 27 Nov 2003 20:57 GMT
/*
* @(#)Animator.java        1.5 99/07/12
*
* Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
*
* Sun grants you ("Licensee") a non-exclusive, royalty free, license to
use,
* modify and redistribute this software in source and binary code form,
* provided that i) this copyright notice and license appear on all copies
of
* the software; and ii) Licensee does not utilize the software in a manner
* which is disparaging to Sun.
*
* This software is provided "AS IS," without a warranty of any kind. ALL

* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
ANY
* IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
* NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
* LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING,
MODIFYING
* OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
ITS
* LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
* INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER

* CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE
OF
* OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*
* This software is not designed or intended for use in on-line control of
* aircraft, air traffic, aircraft navigation or aircraft communications; or
in
* the design, construction, operation or maintenance of any nuclear
* facility. Licensee represents and warrants that it will not use or

* redistribute the Software for such purposes.
*/

import java.awt.*;
import java.awt.event.*;
import java.applet.Applet;
import java.applet.AudioClip;
import java.util.Vector;
import java.util.Hashtable;
import java.util.Enumeration;
import java.net.URL;
import java.net.MalformedURLException;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;

/**
* An applet that plays a sequence of images, as a loop or a one-shot.
* Can have a soundtrack and/or sound effects tied to individual frames.

* See the <a href="http://java.sun.com/applets/applets/Animator/">Animator
* home page</a> for details and updates.
*
* @author Herb Jellinek
* @version 1.5, 07/12/99
*/
public class Animator extends Applet implements Runnable, MouseListener {
   int appWidth = 0;                // Animator width
   int appHeight = 0;               // Animator height
   Thread engine = null;            // Thread animating the images
   boolean userPause = false;       // True if thread currently paused by
user

   boolean loaded = false;          // Can we paint yet?
   boolean error = false;           // Was there an initialization error?
   Animation animation = null;      // Animation this animator contains
   String hrefTarget = null;        // Frame target of reference URL if any
   URL hrefURL = null;              // URL link for information if any

   static final String sourceLocation =
                         "http://java.sun.com/applets/applets/Animator/";

   static final String userInstructions = "shift-click for errors, info";
   static final int STARTUP_ID    = 0;
   static final int BACKGROUND_ID = 1;
   static final int ANIMATION_ID  = 2;

   /**
    * Applet info.
    */
   public String getAppletInfo() {
       return "Animator v1.10 (02/05/97), by Herb Jellinek";
   }

   /**
    * Parameter info.
    */
   public String[][] getParameterInfo() {
       String[][] info = {
           {"imagesource",         "URL",                "a directory"},

           {"startup",         "URL",                "image displayed at
start-up"},
           {"backgroundcolor", "int", "background color (24-bit RGB
number)"},
           {"background",         "URL",               "image displayed as
background"},
           {"startimage",         "int",                "index of first
image"},
           {"endimage",         "int",                "index of last
image"},
           {"namepattern",     "URL",         "generates indexed names"},

           {"images",          "URLs",        "list of image indices"},
           {"href",                "URL",               "page to visit on
mouse-click"},
           {"target",                "name",               "frame to put
that page in"},
           {"pause",                 "int",                "global pause,
milliseconds"},
           {"pauses",                 "ints",     "individual pauses,
milliseconds"},
           {"repeat",                 "boolean",     "repeat? true or
false"},

           {"positions",       "coordinates", "path images will follow"},
           {"soundsource",        "URL",                "audio directory"},
           {"soundtrack",        "URL",                "background music"},
           {"sounds",                "URLs",               "list of audio
samples"},
       };
       return info;
   }

   /**
    * Show a crude "About" box.  Displays credits, errors (if any), and
    * parameter values and documentation.

    */
   void showDescription() {
       DescriptionFrame description = new DescriptionFrame();
       description.tell("\t\t"+getAppletInfo()+"\n");
       description.tell("Updates, documentation at
"+sourceLocation+"\n\n");
       description.tell("Document base: "+getDocumentBase()+"\n");
       description.tell("Code base: "+getCodeBase()+"\n\n");

       Object errors[] = animation.tracker.getErrorsAny();
       if (errors != null) {

           description.tell("Applet image errors:\n");
           for (int i = 0; i < errors.length; i++) {
               if (errors[i] instanceof Image) {
                   AnimationFrame frame = (AnimationFrame)
                                             animation.frames.get(i);
                   URL url = frame.imageLocation;
                   if (url != null) {
                       description.tell(" "+url+" not loaded\n");
                   }

               }
           }
           description.tell("\n");
       }
       if (animation.frames == null || animation.frames.size() == 0)
           description.tell("\n** No images loaded **\n\n");
       description.tell("Applet parameters:\n");
       description.tell(" width = "+getParameter("WIDTH")+"\n");
       description.tell(" height = "+getParameter("HEIGHT")+"\n");
       String params[][] = getParameterInfo();
       for (int i = 0; i < params.length; i++) {

           String name = params[i][0];
           description.tell(" "+name+" = "+getParameter(name)+
                            "\t ["+params[i][2]+"]\n");
       }
       description.show();
   }

   /**
    * Local version of getParameter for debugging purposes.
    */
   public String getParam(String key) {
       String result = getParameter(key);
       return result;
   }

   /**
    * Get parameters and parse them
    */
   public void handleParams() {

       try {
           String param = getParam("IMAGESOURCE");
           animation.imageSource = (param == null) ? getDocumentBase() :
               new URL(getDocumentBase(), param + "/");

           String href = getParam("HREF");
           if (href != null) {
               try {
                   hrefURL = new URL(getDocumentBase(), href);
               } catch (MalformedURLException e) {
                   showParseError(e);
               }

           }

           hrefTarget = getParam("TARGET");
           if (hrefTarget == null)
               hrefTarget = "_top";
           param = getParam("PAUSE");
           if (param != null)
               animation.setGlobalPause(Integer.parseInt(param));
           param = getParam("REPEAT");
           animation.repeat = (param == null) ? true :
               (param.equalsIgnoreCase("yes") ||
                param.equalsIgnoreCase("true"));

           int startImage = 1;
           int endImage = 1;
           param = getParam("ENDIMAGE");
           if (param != null) {
               endImage = Integer.parseInt(param);
               param = getParam("STARTIMAGE");
               if (param != null) {
                   startImage = Integer.parseInt(param);
               }
               param = getParam("NAMEPATTERN");
               animation.prepareImageRange(startImage, endImage, param);

           } else {
               param = getParam("STARTIMAGE");
               if (param != null) {
                   startImage = Integer.parseInt(param);
                   param = getParam("NAMEPATTERN");
                   animation.prepareImageRange(startImage, endImage,
param);
               } else {
                   param = getParam("IMAGES");
                   if (param == null) {
                       showStatus("No legal IMAGES, STARTIMAGE, or ENDIMAGE
"+

                                  "specified.");
                       error = true;
                       return;
                   } else {
                       animation.parseImages(param,
getParam("NAMEPATTERN"));
                   }
               }
           }

           param = getParam("BACKGROUND");
           if (param != null)
               animation.backgroundImageURL = new
URL(animation.imageSource,
                                                      param);

           param = getParam("BACKGROUNDCOLOR");
           if (param != null)
               animation.backgroundColor = decodeColor(param);
           param = getParam("STARTUP");
           if (param != null)
               animation.startUpImageURL = new URL(animation.imageSource,
                                                   param);
           param = getParam("SOUNDSOURCE");
           animation.soundSource = (param == null) ? animation.imageSource

               new URL(getDocumentBase(), param + "/");
           param = getParam("SOUNDS");
           if (param != null)
               animation.parseSounds(param);
           param = getParam("PAUSES");
           if (param != null)
               animation.parseDurations(param);
           param = getParam("POSITIONS");
           if (param != null)
               animation.parsePositions(param);
           param = getParam("SOUNDTRACK");

           if (param != null)
               animation.soundTrackURL = new URL(
                                         animation.soundSource, param);
       } catch (MalformedURLException e) {
           showParseError(e);
       } catch (ParseException e) {
           showParseError(e);
       }
   }

   private Color decodeColor(String s) {
       int val = 0;
       try {
           if (s.startsWith("0x")) {
               val = Integer.parseInt(s.substring(2), 16);

           } else if (s.startsWith("#")) {
               val = Integer.parseInt(s.substring(1), 16);
           } else if (s.startsWith("0") && s.length() > 1) {
               val = Integer.parseInt(s.substring(1), 8);
           } else {
               val = Integer.parseInt(s, 10);
           }
           return new Color(val);
       } catch (NumberFormatException e) {
           return null;
       }
   }

   /**
    * Initialize the applet.  Get parameters.

    */
   public void init() {

       //animation.tracker = new MediaTracker(this);
       appWidth = getSize().width;
       appHeight = getSize().height;
       animation = new Animation(this);
       handleParams();
       animation.init();
       addMouseListener(this);
       Thread me = Thread.currentThread();
       me.setPriority(Thread.MIN_PRIORITY);
       userPause = false;
   }

   public void destroy() {
       removeMouseListener(this);

   }

   void tellLoadingMsg(String file, String fileType) {
       showStatus("Animator: loading "+fileType+" "+file);
   }

   void tellLoadingMsg(URL url, String fileType) {
       tellLoadingMsg(url.toExternalForm(), fileType);
   }

   void clearLoadingMessage() {
       showStatus("");
   }

   void loadError(String fileName, String fileType) {
       String errorMsg = "Animator: Couldn't load "+fileType+" "+
           fileName;
       showStatus(errorMsg);

       System.err.println(errorMsg);
       error = true;
       repaint();
   }

   void loadError(URL badURL, String fileType) {
       loadError(badURL.toExternalForm(), fileType);
   }

   void showParseError(Exception e) {
       String errorMsg = "Animator: Parse error: "+e;
       showStatus(errorMsg);
       System.err.println(errorMsg);
       error = true;
       repaint();
   }

   /**
    * Run the animation. This method is called by class Thread.

    * @see java.lang.Thread
    */
   public void run() {
       Thread me = Thread.currentThread();
       if (animation.frames == null)
           return;
       if ((appWidth <= 0) || (appHeight <= 0))
           return;
       try {
           while (engine == me) {
               // Get current frame and paint it, play its sound
               AnimationFrame thisFrame = (AnimationFrame)
                              animation.frames.get(animation.currentFrame);

               repaint();
               if (thisFrame.sound != null)
                   thisFrame.sound.play();

               animation.currentFrame++;
                // Check if we are done
               if (animation.currentFrame >= animation.frames.size()) {
                   if (animation.repeat)
                       animation.currentFrame = 0;
                   else return;
               }

               // Pause for duration or longer if user paused

               try {
                   Thread.sleep(thisFrame.duration);
                   synchronized(this) {
                       while (userPause) {
                           animation.stopPlaying();
                           wait();
                       }
                   }
               }
               catch (InterruptedException e) {
               }
           }
       } finally {
           synchronized(this) {
           if (engine == me)

               animation.stopPlaying();
           }
       }
   }

   /**
    * No need to clear anything; just paint.
    */
   public void update(Graphics g) {
       paint(g);
   }

   /**
    * Paint the current frame
    */
   public void paint(Graphics g) {
       if (error || ! loaded) {
           if (animation.startUpImage != null) {
               if (animation.tracker.checkID(STARTUP_ID)) {
                   if (animation.backgroundColor != null) {

                       g.setColor(animation.backgroundColor);
                       g.fillRect(0, 0, appWidth, appHeight);
                   }
                   g.drawImage(animation.startUpImage, 0, 0, this);
               }
           } else {
               if ((animation.backgroundImage != null) &&
                    (animation.tracker.checkID(BACKGROUND_ID)))
                       g.drawImage(animation.backgroundImage, 0, 0, this);
               else

                   g.clearRect(0, 0, appWidth, appHeight);
           }
       } else {
           animation.paint(g);
       }
   }

   /**
    * Start the applet by forking an animation thread.
    */
   public void start() {
       engine = new Thread(this);
       engine.start();
       showStatus(getAppletInfo());
   }

   /**
    * Stop the insanity, um, applet.
    */
   public synchronized void stop() {
       engine = null;

       animation.stopPlaying();
        if (userPause) {
           userPause = false;
           notify();
       }
   }

   /**
    * Pause the thread when the user clicks the mouse in the applet.
    * If the thread has stopped (as in a non-repeat performance),
    * restart it.
    */
   public synchronized void mousePressed(MouseEvent event) {
       event.consume();
 
    if ((event.getModifiers() & InputEvent.SHIFT_MASK) != 0) {
           showDescription();

           return;
       } else if (hrefURL != null) {
           //Let mouseClicked handle this.
           return;
       } else if (loaded) {
           userPause = !userPause;
           if (!userPause) {
               animation.startPlaying();
               notifyAll();
           }
       }
   }

   public void mouseClicked(MouseEvent event) {
       if ((hrefURL != null) &&
               ((event.getModifiers() & InputEvent.SHIFT_MASK) == 0)) {

           getAppletContext().showDocument(hrefURL, hrefTarget);
       }
   }

   public void mouseReleased(MouseEvent event) {
   }

   public void mouseEntered(MouseEvent event) {
       showStatus(getAppletInfo()+" -- "+userInstructions);
   }

   public void mouseExited(MouseEvent event) {
       showStatus("");
   }
}

/**
* A class that represents an animation to be displayed by the applet
*/
class Animation extends Object {
   static final int STARTUP_ID    = 0;

   static final int BACKGROUND_ID = 1;
   static final int ANIMATION_ID  = 2;
   static final String imageLabel = "image";
   static final String soundLabel = "sound";

   int globalPause = 1300;        // global pause in milleseconds
   List frames = null;            // List holding frames of animation
   int currentFrame;              // Index into images for current position
   Image startUpImage = null;     // The startup image if any
   Image backgroundImage = null;  // The background image if any

   AudioClip soundTrack = null;   // The soundtrack for this animation
   Color backgroundColor = null;  // Background color if any
   URL backgroundImageURL = null; // URL of background image if any
   URL startUpImageURL = null;    // URL of startup image if any
   URL soundTrackURL = null;      // URL of soundtrack
   URL imageSource = null;        // Directory or URL for images
   URL soundSource = null;        // Directory or URL for sounds
   boolean repeat;                // Repeat the animation if true

   Image offScrImage;             // Offscreen image
   Graphics offScrGC;             // Offscreen graphics context
   MediaTracker tracker;          // MediaTracker used to load images
   Animator owner;                // Applet that contains this animation

   Animation(Animator container) {
       super();
       owner = container;
   }

   void init() {
       tracker = new MediaTracker(owner);
       currentFrame = 0;
       loadAnimationMedia();

       startPlaying();
   }

   void setGlobalPause(int pause) {
       globalPause = pause;
   }

   /**
    * Loads the images and sounds involved with this animation
    */
   void loadAnimationMedia() {
       URL badURL;
       boolean error;
       try {
           if (startUpImageURL != null) {
               owner.tellLoadingMsg(startUpImageURL, imageLabel);
               startUpImage = fetchImageAndWait(startUpImageURL,
STARTUP_ID);

               if (tracker.isErrorID(STARTUP_ID)) {
                   owner.loadError(startUpImageURL, "start-up image");
               }
               owner.repaint();
           }

           if (backgroundImageURL != null) {
                owner.tellLoadingMsg(backgroundImageURL, imageLabel);
               backgroundImage = fetchImageAndWait(backgroundImageURL,
                                                   BACKGROUND_ID);
               if (tracker.isErrorID(BACKGROUND_ID))

                   owner.loadError(backgroundImageURL,
                                       "background image");
               owner.repaint();
           }

           // Fetch the animation frame images
           Iterator iterator = frames.iterator();
           while(iterator.hasNext()) {
               AnimationFrame frame = (AnimationFrame) iterator.next();
               owner.tellLoadingMsg(frame.imageLocation, imageLabel);
               frame.image = owner.getImage(frame.imageLocation);

               tracker.addImage(frame.image, ANIMATION_ID);
               try {
                   tracker.waitForID(ANIMATION_ID);
               } catch (InterruptedException e) {}
           }

           if (soundTrackURL != null && soundTrack == null) {
               owner.tellLoadingMsg(soundTrackURL, imageLabel);
               soundTrack = owner.getAudioClip(soundTrackURL);
               if (soundTrack == null) {
                   owner.loadError(soundTrackURL, "soundtrack");

                   return;
               }
           }

           // Load the sounds into their frames
           iterator = frames.iterator();
           while(iterator.hasNext()) {
               AnimationFrame frame = (AnimationFrame) iterator.next();
               if (frame.soundLocation != null) {
                   owner.tellLoadingMsg(frame.soundLocation, soundLabel);
                   try {
                       frame.sound =
owner.getAudioClip(frame.soundLocation);

                   } catch (Exception ex) {
                       owner.loadError(frame.soundLocation, soundLabel);
                   }
               }
           }

           owner.clearLoadingMessage();
           offScrImage = owner.createImage(owner.appWidth,
owner.appHeight);
           offScrGC = offScrImage.getGraphics();
           offScrGC.setColor(Color.lightGray);
           owner.loaded = true;
           error = false;
       } catch (Exception e) {

           error = true;
           e.printStackTrace();
       }
   }

   /**
    * Fetch an image and wait for it to come in.  Used to enforce a load
    * order for background and startup images.
    */
   Image fetchImageAndWait(URL imageURL, int trackerClass)
                             throws InterruptedException {
       Image image = owner.getImage(imageURL);
       tracker.addImage(image, trackerClass);
       tracker.waitForID(trackerClass);

       return image;
   }

   /**
    * Stuff a range of image names into a List
    * @return a List of image URLs.
    */
   void prepareImageRange(int startImage, int endImage, String pattern)
   throws MalformedURLException {
       frames = new ArrayList(Math.abs(endImage - startImage) + 1);
       if (pattern == null)
           pattern = "T%N.gif";
       if (startImage > endImage) {
           for (int i = startImage; i >= endImage; i--) {

               AnimationFrame frame = new AnimationFrame();
               frames.add(frame);
               frame.duration = globalPause;
               frame.imageLocation = new URL(imageSource,
                                             doSubst(pattern, i+""));
           }
       } else {
           for (int i = startImage; i <= endImage; i++) {
               AnimationFrame frame = new AnimationFrame();
               frames.add(frame);
               frame.duration = globalPause;

               frame.imageLocation = new URL(imageSource,
                                             doSubst(pattern, i+""));
           }
       }
   }

   /**
    * Parse the SOUNDS parameter.  It looks like
    * train.au||hello.au||stop.au, etc., where each item refers to a
    * source image.  Empty items mean that the corresponding image
    * has no associated sound.
    */
   void parseSounds(String attr) throws MalformedURLException {
       int frameIndex = 0;

       int numFrames = frames.size();
       for (int i = 0; (i < attr.length()) && (frameIndex < numFrames); ) {
           int next = attr.indexOf('|', i);
           if (next == -1) next = attr.length();
           String sound = attr.substring(i, next);
           if (sound.length() != 0) {
               AnimationFrame frame = (AnimationFrame)
frames.get(frameIndex);
               frame.soundLocation = new URL(soundSource, sound);
           }
           i = next + 1;

           frameIndex++;
       }
   }

   /**
    * Parse the IMAGES parameter.  It looks like
    * 1|2|3|4|5, etc., where each number (item) names a source image.
    */
   void parseImages(String attr, String pattern)
                          throws MalformedURLException {
       frames = new ArrayList();
       if (pattern == null)
           pattern = "T%N.gif";
       for (int i = 0; i < attr.length(); ) {
           int next = attr.indexOf('|', i);

           if (next == -1) next = attr.length();
           String file = attr.substring(i, next);
           AnimationFrame frame = new AnimationFrame();
           frames.add(frame);
           frame.imageLocation = new URL(imageSource, doSubst(pattern,
file));
           frame.duration = globalPause;
           i = next + 1;
       }
   }

   /**
    * Parse the PAUSES parameter.  It looks like
    * 1000|500|||750, etc., where each item corresponds to a

    * source image.  Empty items mean that the corresponding image
    * has no special duration, and should use the global one.
    *
    * @return a Hashtable of Integer pauses keyed to Integer
    * frame numbers.
    */
   void parseDurations(String attr) {
       int imageNum = 0;
       int numImages = frames.size();
       for (int i = 0; (i < attr.length()) && (imageNum < numImages); ) {
           int next = attr.indexOf('|', i);
           if (next == -1) next = attr.length();

           AnimationFrame aFrame = (AnimationFrame) frames.get(imageNum);
           if (i != next) {
               int duration = Integer.parseInt(attr.substring(i, next));
               aFrame.duration = duration;
           }
           i = next + 1;
           imageNum++;
       }
   }

   /**
    * Parse a String of form xxx@yyy and return a Point.
    */
   Point parsePoint(String s) throws ParseException {
       int atPos = s.indexOf('@');

       if (atPos == -1) throw new ParseException("Illegal position: "+s);
       return new Point(Integer.parseInt(s.substring(0, atPos)),
                        Integer.parseInt(s.substring(atPos + 1)));
   }

   /**
    * Parse the POSITIONS parameter.  It looks like
    * 10@30|11@31|||12@20, etc., where each item is an X@Y coordinate
    * corresponding to a source image.  Empty items mean that the
    * corresponding image has the same position as the preceding one.

    *
    * @return a Hashtable of Points keyed to Integer frame numbers.
    */
   void parsePositions(String param)
   throws ParseException {
       int imageNum = 0;
       int numImages = frames.size();
       for (int i = 0; (i < param.length()) && (imageNum < numImages); ) {
           int next = param.indexOf('|', i);
           if (next == -1)
               next = param.length();
           if (i != next) {
               AnimationFrame frame = (AnimationFrame)
frames.get(imageNum);

               frame.position = parsePoint(param.substring(i, next));
           }
           i = next + 1;
           imageNum++;
       }
   }

   /**
    * Substitute an integer some number of times in a string, subject to
    * parameter strings embedded in the string.
    * Parameter strings:
    *   %N - substitute the integer as is, with no padding.
    *   %<digit>, for example %5 - substitute the integer left-padded with
    *        zeros to <digits> digits wide.

    *   %% - substitute a '%' here.
    * @param inStr the String to substitute within
    * @param theInt the int to substitute, as a String.
    */
   String doSubst(String inStr, String theInt) {
       String padStr = "0000000000";
       int length = inStr.length();
       StringBuffer result = new StringBuffer(length);

       for (int i = 0; i < length;) {
           char ch = inStr.charAt(i);
           if (ch == '%') {
               i++;

               if (i == length) {
                   result.append(ch);
               } else {
                   ch = inStr.charAt(i);
                   if (ch == 'N' || ch == 'n') {
                       // just stick in the number, unmolested
                       result.append(theInt);
                       i++;
                   } else {
                       int pad;
                       if ((pad = Character.digit(ch, 10)) != -1) {
                           // we've got a width value

                           String numStr = theInt;
                           String scr = padStr+numStr;
                           result.append(scr.substring(scr.length() -
pad));
                           i++;
                       } else {
                           result.append(ch);
                           i++;
                       }
                   }
               }
           } else {
               result.append(ch);
               i++;

           }
       }
       return result.toString();
   }

   void startPlaying() {
       if (soundTrack != null)
           soundTrack.loop();
   }

   void stopPlaying() {
       if (soundTrack != null)
           soundTrack.stop();
   }

   public void paint(Graphics g) {
       int xPos = 0;
       int yPos = 0;
       if ((frames.size() > 0) && tracker.checkID(ANIMATION_ID) &&
                                                         (offScrGC !=
null)) {

           AnimationFrame frame = (AnimationFrame)
frames.get(currentFrame);
           Image image = frame.image;
           if (backgroundImage == null) {
               offScrGC.clearRect(0, 0, owner.appWidth, owner.appHeight);
           }
           else
               offScrGC.drawImage(backgroundImage, 0, 0, owner);
           Point pos = null;
           if (frame.position != null) {
               xPos = frame.position.x;
               yPos = frame.position.y;

           }
           if (backgroundColor != null) {
               offScrGC.setColor(backgroundColor);
               offScrGC.fillRect(0, 0, owner.appWidth, owner.appHeight);
               offScrGC.drawImage(image, xPos, yPos, backgroundColor,
owner);
           } else {
               offScrGC.drawImage(image, xPos, yPos, owner);
           }
           if (offScrImage != null)
               g.drawImage(offScrImage, 0, 0, owner);
       }
   }

}

/**
* Instances of this class represent a single frame of an animation
* There can be an image, sound, and position associated with each frame
*/
class AnimationFrame extends Object {
   static final String imageLabel = "image";
   static final String soundLabel = "sound";

   URL imageLocation = null; // Directory or URL of this frames image
   URL soundLocation = null; // Directory or URL of this frames sound
   int duration;             // Duration time for this frame in
milliseconds

   AudioClip sound;          // Sound associated with this frame object
   Image image;              // Image associated with this frame
   Point position;           // Position of this frame

}

/**
* ParseException: signals a parameter parsing problem.
*/
class ParseException extends Exception {
   ParseException(String s) {
       super(s);
   }
}

/**
* DescriptionFrame: implements a pop-up "About" box.
*/
class DescriptionFrame extends Frame implements ActionListener {

   static final int rows = 27;
   static final int cols = 70;
   TextArea info;
   Button cancel;

   DescriptionFrame() {
       super("Animator v1.10");
       add("Center", info = new TextArea(rows, cols));
       info.setEditable(false);
       info.setBackground(Color.white);
       Panel buttons = new Panel();
       add("South", buttons);
       buttons.add(cancel = new Button("Cancel"));
       cancel.addActionListener(this);
       pack();

   }

   public void show() {
       info.select(0,0);
       super.show();
   }

   void tell(String s) {
       info.append(s);
   }

   public void actionPerformed(ActionEvent e) {
       setVisible(false);
   }
}


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.