Applets: Swing Timer, Buttons

In many ways, Swing is an easier to use alternative to AWT. We're going to build GUIs using Swing classes rather than AWT classes because Swing is easier. Caveat! I have found that JButton doesn't work the way I expect. For this reason, I use java.awt.Button rather than javax.swing.JButton.

We've already been importing the package javax.swing.* so that we could use JApplet as a base class for our applets. We could have been using Applet as our base class (only would need java.awt.*), but JApplet simplifies the use of containers for GUIs.

Simple Swing Timer

Here is the API for the Swing Timer: http://download.oracle.com/javase/1.4.2/docs/api/javax/swing/Timer.html The methods of greatest importance to us are: start(), stop(), isRunning(), setDelay().

The API for the ActionListener interface

The API for the ActionListener interface is here: http://download.oracle.com/javase/1.4.2/docs/api/java/awt/event/ActionListener.html We must implement actionPerformed(), which is the code that is executed when a timer "goes off."

Swing Timer

The Swing Timer is a nifty class that lets us set up timers. We can start and stop each timer. We can set a delay time for the timer. When the timer "goes off" the specified "listener" code will be executed. Warning, there is a Timer class in java.util.Timer. We don't want to use that one. We want to use javax.swing.Timer.

Swing Timer constructor

We'll start with the constructor: Timer(int delay, ActionListener listener)
This constructor creates a Timer object that will "notify" all associated listeners every delay milliseconds. The newly created Timer object has one ActionListener associated with it (listener).

Example 1

A small example will help. RectRand.java draws a black rectangle at a random location. Every time you run the applet, the rectangle will appear at a different location. I copy RecRand's paint() here:
public void paint(Graphics g)
    {
        x = gen.nextInt(screenWidth - xsize);
        y = gen.nextInt(screenHeight - ysize);
      
        g.fillRect(x, y, xsize, ysize);
    }

Example 2

In the next applet, Timer1.java, I add a timer that fires every 1000 milliseconds. When the timer fires, the actionPerformed code executes. The actionPerformed code arranges for paint() to be executed in the (near) future: clearing the previous rectangle, then calculating new x,y position and drawing the rectangle.

paint() is ok for a singler Timer

paint() seems reasonable - it's exactly the same as it was in RectRand, however, CAVEAT actually it's peculiar and only works because there's only one timer. With one timer, it is still reasonable to override paint() by using it to directly draw on the relevant Component whenever the state of the applet changes. However, if you have different objects moving independently, and you want the graphics image to display that, you'll need to use repaint() as shown in a later example.
public void paint(Graphics g)					// for RectRand.java
    {
        g.clearRect(x, y, xsize, ysize);
        x = gen.nextInt(screenWidth - xsize);
        y = gen.nextInt(screenHeight - ysize);
      
        g.fillRect(x, y, xsize, ysize);
    }
The timer listener arranges for the drawing of a new rectangle whenever the timer fires:
class TimerListener implements ActionListener {
        
        public void actionPerformed(ActionEvent e) {
            repaint();                                  // arranges for  paint()
        }
    }

Simple Swing Timer, another example

paint() is automatically made ready to run whenever needed. If the applet needs to paint() itself, then your code will call repaint(). In this second example of using the Swing Timer, Timer2.java, I have two different rectangles that are moving at different intervals. The first timer (timer1) moves (randomly) the first rectangle (b1) every 1 second. The second timer (timer2) moves the second rectangle, b2, every 0.5 second.

You'll notice that paint() only draws b1 and b2. paint() is invoked by the TimerListeners whenever their relative timers go off. The timers, as stated in the previous paragraph, update the position of the relative box and calls repaint() (forcing the paint() method to redraw the current position of b1 and b2.


Button to control execution

The first example ButtonDemo.java is an easy one that controls a text string drawn on the canvas.

Here is the relevant code:

public class ButtonDemo extends Applet implements ActionListener
{
    String msg = "";
    Button yes, no, maybe;
    
    public void init()
    {
   
        yes = new Button("YES");
        no = new Button("NO");
        maybe = new Button("MAYBE");
        
        add(yes);
        add(no);
        add(maybe);
        
        yes.addActionListener(this);
        no.addActionListener(this);
        maybe.addActionListener(this);
    }

public void actionPerformed (ActionEvent e) {
        String str = e.getActionCommand();
        if (str.equals("YES")) msg = "You pressed YES";
        else if (str.equals("NO")) msg = "You pressed NO";
        else if (str.equals("MAYBE")) msg = "You pressed maybe";
        else msg = "UH OH!!!";
        
        repaint();
    }
    Notice a few things here:
  1. I'm using Button (java.awt.Button) rather than JButton (javax.swing.JButton). Since I'm not using any Swing component the class ButtonDemo extends Applet (not Japplet).
  2. ButtonDemo implements ActionListener, rather than defining a new class that implements ActionListener.
  3. Because ButtonDemo implements ActionListener, ButtonDemo must implement actionPerformed(). Each button is linked to its actionPerformed through a statement like, e.g., yes.addActionListener(this).
  4. This style of programming actionPerformed must distinguish between different events (there are three different events). It does this through the getActionCommand() method.

    Stop and Start Buttons to turn off and on the animations

    With the Swing Timers, it's now easy to turn on and off the animations by using the Swing Timer's start() and stop() method.

    In Timer1a.java, I've added a start button and a stop button. The start button with turn on Timer timer with timer.start(). The stop button will turn off timer with timer.stop(). Each button will have an ActionListener that listens for the button press.


    Using the mouse

    See the code MouseClicks.java. Mouse information is obtained via two different listeners. A MouseListener, which is used in this applet, and a MouseMotionListener. The MouseListener requires implementation of five methods. In this applet, I'm just repositioning the cat by clicking at a point. The MouseListener takes the (x,y) coordinate and sets the cat's (x,y) to it.

    The GUI examples in Savitch use Threads

      Simple threading examples
    1. Two Threads
    2. Ten Threads
    3. Calculate Primes

    Making a GUI responsive

      Making a GUI responsive (using a single Thread, not the Swing timer)
    1. FillDemo unthreaded and fails
    2. ThreadedFillDemo improved and works
    3. ThreadedFillDemo2 improved (Runnable)
    4. ThreadedFillDemo3 event dispatch thread is made explicit
    5. ThreadedFillDemo4 Thread an inner class


    Another animation example by Kai Horstmann

    1. Ball
    2. BallComponent
    3. BounceThread

    Embedding an applet to a web page

    Many IDEs are able to create an html page with an embedded applet. BlueJ can do this.

    More generally, you can use the <applet> tag in an HTML page:

    <applet code="Circles1.class" width="350" height="350">
    
    Java applet that draws circles.
    </applet>
    
    For an example html document see Circles1.html, and view the source.