Animating a Series of Images

The next example demonstrates animating a series of images that are stored in an array of ImageIcons. The animation presented in Fig. 21.2Fig. 21.3 is implemented using a subclass of JPanel called LogoAnimatorJPanel (Fig. 21.2) that can be attached to an application window or a JApplet. Class LogoAnimator (Fig. 21.3) declares a main method (lines 820 of Fig. 21.3) to execute the animation as an application. Method main declares an instance of class JFrame and attaches a LogoAnimatorJPasnel object to the JFrame to display the animation.

Figure 21.2. Animating a series of images.

(This item is displayed on pages 983 - 984 in the print version)

 1 // Fig. 21.2:
 2 // Animation of a series of images.
 3 import java.awt.Dimension;
 4 import java.awt.event.ActionEvent;
 5 import java.awt.event.ActionListener;
 6 import java.awt.Graphics;
 7 import javax.swing.ImageIcon;
 8 import javax.swing.JPanel;
 9 import javax.swing.Timer;
11 public class LogoAnimatorJPanel extends JPanel
12 {
13 private final static String IMAGE_NAME = "deitel"; // base image name
14 protected ImageIcon images[]; // array of images
15 private final int TOTAL_IMAGES = 30; // number of images
16 private int currentImage = 0; // current image index
17 private final int ANIMATION_DELAY = 50; // millisecond delay
18 private int width; // image width
19 private int height; // image height
21 private Timer animationTimer; // Timer drives animation
23 // constructor initializes LogoAnimatorJPanel by loading images
24 public LogoAnimatorJPanel()
25 {
26 images = new ImageIcon[ TOTAL_IMAGES ];
28 // load 30 images
29 for ( int count = 0; count < images.length; count++ )
30 images[ count ] = new ImageIcon( getClass().getResource(
31  "images/" + IMAGE_NAME + count + ".gif" ) ); 
33 // this example assumes all images have the same width and height
34 width = images[ 0 ].getIconWidth();  // get icon width
35 height = images[ 0 ].getIconHeight(); // get icon height
36 } // end LogoAnimatorJPanel constructor
38 // display current image
39 public void paintComponent( Graphics g )
40 {
41 super.paintComponent( g ); // call superclass paintComponent
43 images[ currentImage ].paintIcon( this, g, 0, 0 );
45 // set next image to be drawn only if timer is running
46 if ( animationTimer.isRunning() )
47 currentImage = ( currentImage + 1 ) % TOTAL_IMAGES;
48 } // end method paintComponent
50 // start animation, or restart if window is redisplayed
51 public void startAnimation()
52 {
53 if ( animationTimer == null )
54 {
55 currentImage = 0; // display first image
57 // create timer 
58 animationTimer = 
59  new Timer( ANIMATION_DELAY, new TimerHandler() );
61 animationTimer.start(); // start timer
62 } // end if
63 else // animationTimer already exists, restart animation
64 {
65 if ( ! animationTimer.isRunning() )
66 animationTimer.restart();
67 } // end else
68 } // end method startAnimation
70 // stop animation timer
71 public void stopAnimation()
72 {
73 animationTimer.stop();
74 } // end method stopAnimation
76 // return minimum size of animation
77 public Dimension getMinimumSize()  
78 { 
79  return getPreferredSize(); 
80 } // end method getMinimumSize 
82 // return preferred size of animation 
83 public Dimension getPreferredSize() 
84 { 
85  return new Dimension( width, height );
86 } // end method getPreferredSize 
88 // inner class to handle action events from Timer
89 private class TimerHandler implements ActionListener
90 {
91 // respond to Timer's event
92 public void actionPerformed( ActionEvent actionEvent )
93 {
94 repaint(); // repaint animator
95 } // end method actionPerformed
96 } // end class TimerHandler
97 } // end class LogoAnimatorJPanel

Figure 21.3. Displaying animated images on a JFrame.

(This item is displayed on page 985 in the print version)

 1 // Fig. 21.3:
 2 // Animation of a series of images.
 3 import javax.swing.JFrame;
 5 public class LogoAnimator
 6 {
 7 // execute animation in a JFrame
 8 public static void main( String args[] )
 9 {
10 LogoAnimatorJPanel animation = new LogoAnimatorJPanel();
12 JFrame window = new JFrame( "Animator test" ); // set up window
13 window.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
14 window.add( animation ); // add panel to frame
16 window.pack(); // make window just large enough for its GUI
17 window.setVisible( true ); // display window
19 animation.startAnimation(); // begin animation
20 } // end main
21 } // end class LogoAnimator

Class LogoAnimatorJPanel (Fig. 21.2) maintains an array of ImageIcons that are loaded in the constructor (lines 2436). Lines 2931 create each ImageIcon object and store the animation's 30 images in array images. The constructor argument uses string concatenation to assemble the file name from the pieces "images/", IMAGE_NAME, count and ".gif". Each image in the animation is in a file called deitel# .gif, where # is a value in the range 029 specified by the loop's control variable count. Lines 3435 determine the width and height of the animation from the size of the first image in array imageswe assume that all the images have the same width and height.

After the LogoAnimatorJPanel constructor loads the images, method main of Fig. 21.3 sets up the window in which the animation will appear (lines 1217), and line 19 calls the LogoAnimatorJPanel's startAnimation method (declared at lines 5168 of Fig. 21.2). This method starts the program's animation for the first time or restarts the animation that the program stopped previously. [Note: This method is called when the program is first run, to begin the animation. Although we provide the functionality for this method to restart the animation if it has been stopped, the example does not call the method for this purpose. We have added the functionality, however, should the reader choose to add GUI components that enable the user to start and stop the animation.] For example, to make an animation "browser friendly" in an applet, the animation should stop when the user switches Web pages. If the user returns to the Web page with the animation, method startAnimation can be called to restart the animation. The animation is driven by an instance of class Timer (from package javax.swing). A Timer generates ActionEvents at a fixed interval in milliseconds (normally specified as an argument to the Timer's constructor) and notifies all its ActionListeners each time an ActionEvent occurs. Line 53 determines whether the Timer reference animationTimer is null. If it is, method startAnimation is being called for the first time, and a Timer needs to be created so that the animation can begin. Line 55 sets currentImage to 0, which indicates that the animation should begin with the image in the first element of array images. Lines 5859 assign a new Timer object to animationTimer. The Timer constructor receives two argumentsthe delay in milliseconds (ANIMATION_DELAY is 50, as specified in line 17) and the ActionListener that will respond to the Timer's ActionEvents. For the second argument, an object of class TimerHandler is created. This class, which implements ActionListener, is declared in lines 8996. Line 61 starts the Timer object. Once started, animationTimer will generate an ActionEvent every 50 milliseconds. Each time an ActionEvent is generated, the Timer's event handler actionPerformed (lines 9295) is called. Line 94 calls LogoAnimatorJPanel's repaint method to schedule a call to LogoAnimatorJPanel's paintComponent method (lines 3948). Remember that any subclass of JComponent that draws should do so in its paintComponent method. Recall from Chapter 11 that the first statement in any paintComponent method should be a call to the superclass's paintComponent method, to ensure that Swing components are displayed correctly.

If the animation was started earlier, then our Timer has been created and the condition in line 53 will evaluate to false. The program will continue with lines 6566, which restart the animation that the program stopped previously. The if condition at line 65 uses Timer method isRunning to determine whether the Timer is running (i.e., generating events). If it is not running, line 66 calls Timer method restart to indicate that the Timer should start generating events again. Once this occurs, method actionPerformed (the Timer's event handler) is again called at regular intervals. Each time, a call is made to method repaint (line 94), causing method paintComponent to be called and the next image to be displayed.

Line 43 paints the ImageIcon stored at element currentImage in the array. Lines 4647 determine whether the animationTimer is running and, if so, prepare for the next image to be displayed by incrementing currentImage by 1. The remainder calculation ensures that the value of currentImage is set to 0 (to repeat the animation sequence) when it is incremented past 29 (the last element index in the array). The if statement ensures that the same image will be displayed if paintComponent is called while the Timer is stopped. This could be useful if a GUI is provided that enables the user to start and stop the animation. For example, if the animation is stopped and the user covers it with another window, then uncovers it, method paintComponent will be called. In this case, we do not want the animation to show the next image (because the animation has been stopped). We simply want the window to display the same image until the animation is restarted.

Method stopAnimation (lines 7174) stops the animation by calling Timer method stop to indicate that the Timer should stop generating events. This prevents actionPerformed from calling repaint to initiate the painting of the next image in the array. [Note: Just as with restarting the animation, this example defines but does not use method stopAnimation. We have provided this method for demonstration purposes, or if the user wishes to modify this example so that it enables the user to stop and restart the animation.]

Software Engineering Observation 21.1

When creating an animation for use in an applet, provide a mechanism for disabling the animation when the user browses a new Web page different from the one on which the animation applet resides.

Remember that by extending class JPanel, we are creating a new GUI component. Thus, we must ensure that our new component works like other components for layout purposes. Layout managers often use a GUI component's getPreferredSize method (inherited from class java.awt.Component) to determine the preferred width and height of the component when laying it out as part of a GUI. If a new component has a preferred width and height, it should override method getPreferredSize (lines 8386) to return that width and height as an object of class Dimension (package java.awt). The Dimension class represents the width and height of a GUI component. In this example, the images are 160 pixels wide and 80 pixels tall, so method getPreferredSize returns a Dimension object containing the numbers 160 and 80 (determined at lines 3435).

Look-and-Feel Observation 21.1

The default size of a JPanel object is 10 pixels wide and 10 pixels tall.

Look-and-Feel Observation 21.2

When subclassing JPanel (or any other JComponent), override method getPreferredSize if the new component is to have a specific preferred width and height.

Lines 7780 override method getMinimumSize. This method determines the minimum width and height of the component. As with method getPreferredSize, new components should override method getMinimumSize (also inherited from class Component). Method getMinimumSize simply calls getPreferredSize (a common programming practice) to indicate that the minimum size and preferred size are the same. Some layout managers ignore the dimensions specified by these methods. For example, a BorderLayout's NORTH and SOUTH regions use only the component's preferred height.

Look-and-Feel Observation 21.3

If a new GUI component has a minimum width and height (i.e., smaller dimensions would render the component ineffective on the display), override method getMinimumSize to return the minimum width and height as an instance of class Dimension.

Look-and-Feel Observation 21.4

For many GUI components, method getMinimumSize is implemented to return the result of a call to the component's getPreferredSize method.

Introduction to Computers, the Internet and the World Wide Web

Introduction to Java Applications

Introduction to Classes and Objects

Control Statements: Part I

Control Statements: Part 2

Methods: A Deeper Look


Classes and Objects: A Deeper Look

Object-Oriented Programming: Inheritance

Object-Oriented Programming: Polymorphism

GUI Components: Part 1

Graphics and Java 2D™

Exception Handling

Files and Streams


Searching and Sorting

Data Structures



Introduction to Java Applets

Multimedia: Applets and Applications

GUI Components: Part 2



Accessing Databases with JDBC


JavaServer Pages (JSP)

Formatted Output

Strings, Characters and Regular Expressions

Appendix A. Operator Precedence Chart

Appendix B. ASCII Character Set

Appendix C. Keywords and Reserved Words

Appendix D. Primitive Types

Appendix E. (On CD) Number Systems

Appendix F. (On CD) Unicode®

Appendix G. Using the Java API Documentation

Appendix H. (On CD) Creating Documentation with javadoc

Appendix I. (On CD) Bit Manipulation

Appendix J. (On CD) ATM Case Study Code

Appendix K. (On CD) Labeled break and continue Statements

Appendix L. (On CD) UML 2: Additional Diagram Types

Appendix M. (On CD) Design Patterns

Appendix N. Using the Debugger

Inside Back Cover

Java(c) How to Program
Java How to Program (6th Edition) (How to Program (Deitel))
ISBN: 0131483986
EAN: 2147483647
Year: 2003
Pages: 615 © 2008-2020.
If you may any questions please contact us: