The Java TM Tutorial

| Start of Tutorial > Start of Trail > Start of Lesson | Search

Trail: Creating a GUI with JFC/Swing
Lesson: Working with Graphics

## Creating an Animation Loop with Timer

> Every program that performs animation by painting at regular intervals needs an animation loop. Generally, this loop should be in its own thread. It should never be in the `paintComponent` method, since that would take over the event-dispatching thread, which is in charge of painting and event handling.

> The `Timer` class makes implementing an animation loop easy. This section provides two `Timer`-based templates for performing animation, one for applets and another for applications. The applet version is pictured below. When running the applet, you can click on it to stop the animation. Click again to restart it.

> This is a picture of the applet's GUI. To run the applet, click the picture. The applet will appear in a new browser window.
> The animation the template performs is a bit boring: it simply displays the current frame number, using a default rate of 10 frames per second. The next few sections build on this example, showing you how to animate images.

> You can find the code for the applet version of the animation template in `AnimatorAppletTimer.java`. The code for the application version is in `AnimatorApplicationTimer.java`. The rest of this section explains the templates' common code. Here is a summary of what both templates do:

> >     public class AnimatorClass ... implements ActionListener {
> >         int frameNumber = -1;
> >         Timer timer;
> >         boolean frozen = false;
> >         JLabel label;

> >         //In initialization code:
> >             //From user-specified frames-per-second value, determine
> >             //how long to delay between frames.
> >             ...
> >             //Set up a timer that calls this object's action handler.
> >             timer = new Timer(delay, this);
> >             ...
> >             //Set up the components in the GUI.

> >         public synchronized void startAnimation() {
> >             ...
> >             timer.start();
> >             ...
> >         }

> >         public synchronized void stopAnimation() {
> >             ...
> >             timer.stop();
> >             ...
> >         }

> >         public void actionPerformed(ActionEvent e) {
> >             //Advance the animation frame.
> >             frameNumber++;

> >             //Request that the frame be painted.
> >             label.setText("Frame " + frameNumber);
> >         }
> >         ...
> >         //When the application's GUI appears:
> >             startAnimation();
> >         ...
> >     }

### Initializing Instance Variables

> The animation templates use four instance variables. The first (`frameNumber`) represents the current frame. It's initialized to -1, even though the first frame number is 0. The reason: the frame number is incremented at the start of the animation loop, before the first frame is painted. Thus, the first frame to be painted is frame 0.

> The second instance variable (`timer`) is the `Timer` object that implements the animation loop. It's initialized to fire an action event every `delay` milliseconds.

> The `delay` variable is a local variable that's initialized using a frames per second number provided by the user. The following code converts frames per second into the number of milliseconds between frames:

> >     delay = (fps > 0) ? (1000 / fps) : 100;

> The `?` `:` notation in the previous code snippet is shorthand for `if` `else`. If the user provides a number of frames per second greater than 0, then the delay is 1000 milliseconds divided by the number of frames per second. Otherwise, the delay between frames is 100 milliseconds (ten frames per second).

> The third instance variable (`frozen`) is a boolean value that's initialized to `false`. The templates set it to `true` when the user requests that the animation stop. You'll see more about this later in this section.

> The fourth instance variable (`label`) is a reference to the component that performs the painting.

### The Animation Loop

> The `Timer` object implements the animation loop by continuously firing action events every `delay` milliseconds. In response to each action event, the `actionPerformed` method does the following:
> 1. Advances the frame number.
> 2. Requests that the current frame of animation be painted.

> For more information about timers, see How to Use Timers.

### Behaving Politely

> Two more features of the animation templates belong in the category of polite behavior.

> The first feature is allowing the user to explicitly stop (and restart) the animation, while the applet or application is still visible. Animation can be quite distracting, and it's a good idea to give the user the power to stop the animation so that the user can concentrate on something else. This feature is implemented by overriding the `mousePressed` method so that it stops or starts the timer, depending on the program's current state. Here's the code that implements this:

> >     ...//In initialization code:
> >     boolean frozen = false;
> >     ...
> >     public synchronized void startAnimation() {
> >         if (frozen) {
> >             //Do nothing.  The user has requested that we
> >             //stop changing the image.
> >         } else {
> >             //Start animating!
> >             ...
> >             timer.start();
> >             ...
> >         }

> >     public synchronized void stopAnimation() {
> >         ...
> >         timer.stop();
> >         ...
> >     }
> >     ...
> >     //In a mouse listener registered on the animating component:
> >     public void mousePressed(MouseEvent e) {
> >         if (frozen) {
> >             frozen = false;
> >             startAnimation();
> >         } else {
> >             frozen = true;
> >             stopAnimation();
> >         }
> >     }

> The second feature is suspending the animation whenever the applet or application is known not to be visible. For the applet animation template, this is achieved by implementing the `Applet` `stop` and `start` methods to call `stopAnimation` and `startAnimation`, respectively. For the application animation template, this is achieved by implementing a window event handler that reacts to iconification and deiconification by, again, calling `stopAnimation` and `startAnimation`, respectively.

> In both templates, if the user hasn't frozen the animation, then when the program detects that the animation isn't visible, it tells the timer to stop. When the user revisits the animation, the program restarts the timer, unless the user has explicitly requested that the animation be stopped.

| Start of Tutorial > Start of Trail > Start of Lesson | Search