Sun Java Solaris Communities My SDN Account Join SDN
 
Article

Using Timers in Swing Applications

 

Using Timers in Swing Applications

By Hans Muller and Kathy Walrath

Programs -- especially those that present GUIs -- often need to perform a task either repeatedly or after a delay (or both). Timers make it easy for you to schedule the task. As of 1.3, the Java platform provides two Timer classes -- one in the javax.swing package and the other in java.util.

This article describes how to choose and use the appropriate Timer class for your Swing application. We discuss the problems that timers solve, give guidelines for choosing the right solution, and provide examples using timers.

What Timers Do

Generally speaking, a timer supports executing some task periodically or just once at some future time. Timers are important, albeit specialized, tools for the GUI programmer because they simplify the job of scheduling activity that results in a screen update. GUI applications typically use timers for animation, such as for blinking a cursor, or for timing responses, such as popping up a tool tip when the mouse is still for a few moments.

Nearly every computer platform has a timer facility of some kind. For example, UNIX programs can use the alarm function to schedule a SIGALRM signal; a signal handler can then perform the task. The Win32 API has functions such as SetTimer that let you schedule and manage timer callbacks. The Java platform's timer facility includes the same basic functionality as other platforms, and it's relatively easy to configure and extend.

Code Without Timers

In programs written without the benefit of timers, you'll see some rather nasty code for providing delays or periodic task execution. The nastiest algorithm of all is the busy wait loop. This little embarassment attempts to create a delay by keeping the CPU busy:

//DON'T DO THIS!
while (isCursorBlinking()) {
    drawCursor();
    for (int i = 0; i < 300000; i++) {
	Math.sqrt((double)i); // this should really chew up some time
    }
    eraseCursor();
    for (int i = 0; i < 300000; i++) {
	Math.sqrt((double)i); // likewise
    }
}
    

The reasons why busy wait loops are a bad idea are legion and obvious, so we won't enumerate them here.

A common, relatively practical approach to creating delays or timed loops is to create a new thread that sleeps before executing its task. Using the Thread sleep method to time the delay works well with Swing components as long as you follow the rules for thread usage outlined in the article Threads and Swing. The previous example could be sensibly rewritten like this:

final Runnable doUpdateCursor = new Runnable() {
    boolean shouldDraw = false;
    public void run() {
	if (shouldDraw = !shouldDraw) {
	    drawCursor();
	} else {
	    eraseCursor();
	}
    }
};

Runnable doBlinkCursor = new Runnable() {
    public void run() {
	while (isCursorBlinking()) {
	    try {
		EventQueue.invokeLater(doUpdateCursor);
		Thread.sleep(300);
	    }
	    catch (InterruptedException e) {
		return;
	    }
	}
    }
};

new Thread(doBlinkCursor).start();
    

As you can see, we've used the invokeLater method to ensure that the draw and erase methods execute on the event-dispatching thread. The main problem with this approach is that it doesn't scale well. Threads and thread scheduling aren't free or even as cheap as one might hope, so in a system where there may be many busy threads it's unwise to allocate a thread for every delay or timing loop.

The Swing Timer Class

The javax.swing.Timer class allows you to schedule an arbitrary number of periodic or delayed actions with just one thread. This Timer class is used by Swing components for things like blinking the text cursor and for timing tool-tip appearances and disappearances.

The Swing timer implementation fires an action event whenever the specified interval or delay time passes. You need to provide an Action object to the timer. Implement the Action's actionPerformed method to perform the desired task. For example, the blinking cursor example above could be written like this:

Action updateCursorAction = new AbstractAction() {
    boolean shouldDraw = false;
    public void actionPerformed(ActionEvent e) {
	if (shouldDraw = !shouldDraw) {
	    drawCursor();
	} else {
	    eraseCursor();
	}
    }
};

new Timer(300, updateCursorAction).start();
    

In this example we're using a timer to blink the cursor every 300 milliseconds.

The important difference between using the Swing Timer class and creating your own Thread is that the Swing Timer class uses just one thread for all timers. It deals with scheduling actions and putting its thread to sleep internally in a way that scales to large numbers of timers. The other important feature of this timer class is that the Action's actionPerformed method runs on the event dispatching thread. As a result, you don't have to bother with an explicit invokeLater call.

The Utility Timer and TimerTask Classes

Timers aren't the exclusive domain of GUI applications. In version 1.3 of the Java platform, support for timers was added to the java.util package. Like the Swing timer class, the main java.util timer class is called Timer. (We'll call it the "utility Timer class" to differentiate from the Swing Timer class.) Instead of scheduling Actions, the utility Timer class schedules instances of a class called TimerTask.

The utility timer facility has a different division of labor from the Swing version. For example, you control the utility timer facility by invoking methods on TimerTask rather than on Timer. Still, both timer facilities have the same basic support for delayed and periodic execution.

The utility timer facility provides more flexibility over scheduling timers. For example, the utility timer lets you can specify whether a timer task is to run at a fixed rate or repeatedly after a fixed delay. The latter scheme, which is the only one supported by Swing timers, means that a timer's frequency can drift because of extra delays introduced by the garbage collector or by long-running timer tasks. This drift is acceptable for animations or auto-repeating a keyboard key, but it's not appropriate for driving a clock or in situations where multiple timers must effectively be kept in lockstep.

The most important difference between javax.Swing.Timer and java.util.Timer is that the latter doesn't run its tasks on the event-dispatching thread.

Here's one final version of the blinking cursor example. This one uses the new javax.util.Timer class.

final Runnable doUpdateCursor = new Runnable() {
    private boolean shouldDraw = false;
    public void run() {
	if (shouldDraw = !shouldDraw) {
	    drawCursor();
	} 
	else {
	    eraseCursor();
	}
    }
};

TimerTask updateCursorTask = new TimerTask() {
    public void run() {
	EventQueue.invokeLater(doUpdateCursor);
    }
};

myGlobalTimer.schedule(updateCursorTask, 0, 300);
    

One other important difference to note here is that each java.util.Timer instance, such as myGlobalTimer in the previous example, corresponds to a single thread. It's up to applications to manage one or more Timer objects.

How to Choose a Timer Class

As we've seen, the Swing and utility timer facilities provide roughly the same functionality. Generally speaking, we recommend that you use the utility classes if you're writing a self contained application, particularly one that's not GUI related. The Swing Timer class is preferred if you're building a new Swing component or module that doesn't require large numbers of timers (where "large" means dozens or more).

The new utility timer classes give you control over how many timer threads are created; each java.util.Timer object creates one thread. If your application requires large numbers of timers you might want to create several java.util.Timer objects and have each one schedule related TimerTasks. In a typical application you'll share just one global Timer object, for which you'll need to create one statically scoped Timer field or property.

The Swing Timer class uses a single private thread to schedule timers. A typical GUI component or application uses at most a handful of timers to control various animation and popup effects. The single thread is more than sufficient for this.

The other important difference between the two facilities is that Swing timers run their task on the event dispatching thread, while utility timers do not. You can hide this difference with a TimerTask subclass that takes care of calling invokeLater. Here is an example:

abstract class SwingTimerTask extends java.util.TimerTask {
    public abstract void doRun();
    public void run() {
	if (!EventQueue.isDispatchThread()) {
	    EventQueue.invokeLater(this);
	} else {
	    doRun();
	}
    }
}
    

To implement the task, you would then create a SwingTimerTask subclass and override its doRun method (instead of run).

An Example

Here's an example that demonstrates an interesting way to use timers. This example uses the new utility Timer and TimerTask classes, even though the Swing Timer class would have worked just as well, because you can already find good examples of using the Swing Timer class.

To look at the source, or download the demo, here are the necessary files:

Most of the code is fairly self-explanatory , so we'll just highlight a few key points. In this example a TimerTask is used to schedule repaints about as quickly as the application can handle them. The paintComponent method that handles the fade operation (see ImagePanel.paintComponent in the example sources) computes how far along the fade is supposed to be based on the current time, and then paints accordingly.

The code that estimates that maximum frame rate is important because the performance of machines running the Java platform can easily vary by a factor of 10. Here's the method that does this:

public long computeFrameRate() {
    Graphics g = createImage(imageWidth, imageHeight).getGraphics();
    long dt = 0;
    paintComponent(g);
    for (int i = 0; i < 10; i++) {
	long startTime = System.currentTimeMillis();
	paintComponent(g);
	dt += System.currentTimeMillis() - startTime;
    }
    return (long)((float)(dt / 10) * 1.1f);
}
    

We're just measuring the average time the main paintComponent method needs to draw the display on an offscreen image, plus 10%. This value will become the rate for the TimerTask that drives the fade animation. Note that we're stuck with a heuristic - running the loop 10 times - which reduces the effect of HotSpot style compilation. We also run the paintComponent method once before timing it, to avoid timing the class loader. To keep the example simple, the timing loop runs the first time the user presses the Fade button. In a real application, using a worker thread to compute the frame rate when the application started would be preferable. For more information, see the article Using a Swing Worker Thread.

Summary

This section introduced you to the Swing and utility timer facilities. For further information and examples of using Swing timers, see The Java Tutorial section How to Use Timers. Also see the API documentation for javax.swing.Timer. The utility timer facilities are described in the API documentation for java.util.Timer and java.util.TimerTask.

Last modified: Fri Mar 17 08:52:26 PST 2000