animator.java
来自「《移动Agent技术》一书的所有章节源代码。」· Java 代码 · 共 1,135 行 · 第 1/2 页
JAVA
1,135 行
/*
* @(#)Animator.java 1.10 97/02/05
*
* 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;
/**
* 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.10, 02/05/97
*/
public class Animator extends Applet
implements Runnable,
MouseListener {
/**
* The images, in display order (Images).
*/
Vector images = null;
/**
* A table that maps images to image names - for error messages.
*/
Hashtable imageNames = new Hashtable(10);
/**
* Duration of each image (Integers, in milliseconds).
*/
Hashtable durations = null;
/**
* Sound effects for each image (AudioClips).
*/
Hashtable sounds = null;
/**
* Position of each image (Points).
*/
Hashtable positions = null;
/**
* MediaTracker 'class' ID numbers.
*/
static final int STARTUP_ID = 0;
static final int BACKGROUND_ID = 1;
static final int ANIMATION_ID = 2;
/**
* Start-up image URL, if any.
*/
URL startUpImageURL = null;
/**
* Start-up image, if any.
*/
Image startUpImage = null;
/**
* Background image URL, if any.
*/
URL backgroundImageURL = null;
/**
* Background image, if any.
*/
Image backgroundImage = null;
/**
* Background color, if any.
*/
Color backgroundColor = null;
/**
* The soundtrack's URL.
*/
URL soundtrackURL = null;
/**
* The soundtrack.
*/
AudioClip soundtrack = null;
/**
* URL to link to, if any.
*/
URL hrefURL = null;
/**
* Frame target for that URL, if any.
*/
String hrefTarget = null;
/**
* Our width.
*/
int appWidth = 0;
/**
* Our height.
*/
int appHeight = 0;
/**
* The directory or URL from which the images are loaded
*/
URL imageSource = null;
/**
* The directory or URL from which the sounds are loaded
*/
URL soundSource = null;
/**
* The thread animating the images.
*/
Thread engine = null;
/**
* The current loop slot - index into 'images.'
*/
int frameNum;
/**
* frameNum as an Object - suitable for use as a Hashtable key.
*/
Integer frameNumKey;
/**
* The current X position (for painting).
*/
int xPos = 0;
/**
* The current Y position (for painting).
*/
int yPos = 0;
/**
* The default number of milliseconds to wait between frames.
*/
public static final int defaultPause = 3900;
/**
* The global delay between images, which can be overridden by
* the PAUSE parameter.
*/
int globalPause = defaultPause;
/**
* Whether or not the thread has been paused by the user.
*/
boolean userPause = false;
/**
* Repeat the animation? If false, just play it once.
*/
boolean repeat;
/**
* The offscreen image, used in double buffering
*/
Image offScrImage;
/**
* The offscreen graphics context, used in double buffering
*/
Graphics offScrGC;
/**
* The MediaTracker we use to load our images.
*/
MediaTracker tracker;
/**
* Can we paint yet?
*/
boolean loaded = false;
/**
* Was there an initialization error?
*/
boolean error = false;
/**
* What we call an image file in messages.
*/
static final String imageLabel = "image";
/**
* What we call a sound file in messages.
*/
static final String soundLabel = "sound";
/**
* Print silly debugging info?
*/
static final boolean debug = false;
/**
* Where to find the source code and documentation - for informational
* purposes.
*/
static final String sourceLocation =
"http://java.sun.com/applets/applets/Animator/";
/**
* Instructions to the user: how to produce the popup.
*/
static final String userInstructions = "shift-click for errors, info";
/**
* 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", "color (24-bit RGB number) displayed as background"},
{"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[] = tracker.getErrorsAny();
if (errors != null) {
description.tell("Applet image errors:\n");
for (int i = 0; i < errors.length; i++) {
if (errors[i] instanceof Image) {
URL url = (URL)imageNames.get((Image)errors[i]);
if (url != null) {
description.tell(" "+url+" not loaded\n");
}
}
}
description.tell("\n");
}
if (images == null || images.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();
}
/**
* Print silly debugging info to the standard output.
*/
void dbg(String s) {
if (debug) {
System.out.println("> "+s);
}
}
/**
* Local version of getParameter for debugging purposes.
*/
public String getParam(String key) {
String result = getParameter(key);
dbg("getParameter("+key+") = "+result);
return result;
}
final int setFrameNum(int newFrameNum) {
frameNumKey = new Integer(frameNum = newFrameNum);
return frameNum;
}
/**
* Parse the IMAGES parameter. It looks like
* 1|2|3|4|5, etc., where each number (item) names a source image.
*
* @return a Vector of (URL) image file names.
*/
Vector parseImages(String attr, String pattern)
throws MalformedURLException {
if (pattern == null) {
pattern = "T%N.gif";
}
Vector result = new Vector(10);
for (int i = 0; i < attr.length(); ) {
int next = attr.indexOf('|', i);
if (next == -1) next = attr.length();
String file = attr.substring(i, next);
result.addElement(new URL(imageSource, doSubst(pattern, file)));
i = next + 1;
}
return result;
}
/**
* Fetch an image and wait for it to come in. Used to enforce a load
* order for background and startup images.
* Places URL and image in imageNames table.
*/
Image fetchImageAndWait(URL imageURL, int trackerClass)
throws InterruptedException {
Image image = getImage(imageURL);
tracker.addImage(image, trackerClass);
imageNames.put(image, imageURL);
tracker.waitForID(trackerClass);
return image;
}
/**
* Fetch the images named in the argument. Is restartable.
*
* @param images a Vector of URLs
* @return true if all went well, false otherwise.
*/
boolean fetchImages(Vector images) {
if (images == null) {
return true;
}
int size = images.size();
for (int i = 0; i < size; i++) {
Object o = images.elementAt(i);
if (o instanceof URL) {
URL url = (URL)o;
tellLoadingMsg(url, imageLabel);
Image im = getImage(url);
tracker.addImage(im, ANIMATION_ID);
images.setElementAt(im, i);
imageNames.put(im, url);
}
}
try {
tracker.waitForID(ANIMATION_ID);
} catch (InterruptedException e) {}
if (tracker.isErrorID(ANIMATION_ID)) {
return false;
}
return true;
}
/**
* 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.
*
* @return a Hashtable of SoundClips keyed to Integer frame numbers.
*/
Hashtable parseSounds(String attr, Vector images)
throws MalformedURLException {
Hashtable result = new Hashtable();
int imageNum = 0;
int numImages = images.size();
for (int i = 0; i < attr.length(); ) {
if (imageNum >= numImages) break;
int next = attr.indexOf('|', i);
if (next == -1) next = attr.length();
String sound = attr.substring(i, next);
if (sound.length() != 0) {
result.put(new Integer(imageNum),
new URL(soundSource, sound));
}
i = next + 1;
imageNum++;
}
return result;
}
/**
* Fetch the sounds named in the argument.
* Is restartable.
*
* @return URL of the first bogus file we hit, null if OK.
*/
URL fetchSounds(Hashtable sounds) {
for (Enumeration e = sounds.keys() ; e.hasMoreElements() ;) {
Integer num = (Integer)e.nextElement();
Object o = sounds.get(num);
if (o instanceof URL) {
URL file = (URL)o;
tellLoadingMsg(file, soundLabel);
try {
sounds.put(num, getAudioClip(file));
} catch (Exception ex) {
return file;
}
}
}
return null;
}
/**
* 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.
*/
Hashtable parseDurations(String attr, Vector images) {
Hashtable result = new Hashtable();
int imageNum = 0;
int numImages = images.size();
for (int i = 0; i < attr.length(); ) {
if (imageNum >= numImages) break;
int next = attr.indexOf('|', i);
if (next == -1) next = attr.length();
if (i != next) {
int duration = Integer.parseInt(attr.substring(i, next));
result.put(new Integer(imageNum), new Integer(duration));
} else {
result.put(new Integer(imageNum),
new Integer(globalPause));
}
i = next + 1;
imageNum++;
}
return result;
}
/**
* 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.
*/
Hashtable parsePositions(String param, Vector images)
throws ParseException {
Hashtable result = new Hashtable();
int imageNum = 0;
int numImages = images.size();
for (int i = 0; i < param.length(); ) {
if (imageNum >= numImages) break;
int next = param.indexOf('|', i);
if (next == -1) next = param.length();
if (i != next) {
result.put(new Integer(imageNum),
parsePoint(param.substring(i, next)));
}
i = next + 1;
imageNum++;
}
return result;
}
/**
* Get the dimensions of an image.
* @return the image's dimensions.
*/
Dimension getImageDimensions(Image im) {
return new Dimension(im.getWidth(null), im.getHeight(null));
}
/**
* 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.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?