CS 3230 - Chap 8 Notes

Event Handling

In this week's exciting episode, we'll learn how to listen for events generated from button clicks, key presses, etc.

Event Handling Basics (p.278)

Event: "Something happened". Examples: mouse click, mouse drag, key down, key up, window resize, etc.

Event Source: A component that generates an event, such a a button, menu, checkbox, etc.

Event Listener: A component that catches and responds to events generated by a source. Any class can be a listener by implementing a specific listener interface.

Event Object: An object sent by a source to a listener. Contains details about the particular event that occurred.

Three Ways to Handle an Event

Like the GUI toolkits, the way you handle events has changed significantly over time. Here are three ways to handle an event.

#1: Implement a Listener

The first way is to have a class (usually your Frame, but it can be any class) implement some *Listener interface and override it's methods to listen for events. Example:

public class MyFrame extends JFrame
	implements ActionListener
{
	...

	// this method is inherited from ActionListener and must be overridden
	public void actionPerformed(ActionEvent e) {
		...
	}
}

Source code: ImplementsListener.java - Frame implements a listener to handle a button event.

The alert student will note that there is a problem with the above approach: the frame can only handle events from one button. This is somewhat limiting. Thankfully, the Java designers have blessed us with the ability to distinguish between different event sources by calling setActionCommand on the event sources, and getActionCommand in the event handler.

Source code: UsesActionCommands.java - frame implements a listener but can distinguish between different buttons by testing the action command.

#2: Subclass an Adapter

Some of the *Listener interfaces are designed to handle numerous different events. Consequently, they have a whole schload of methods, such as the WindowListener. However, sometimes you're only interested in one or two of those events. This can lead to ugly code like:

class MyFrame extends Frame implements WindowListener {
	MyFrame() {
		addWindowListener(this);
		...
	}

	...

	// This is the only event we are interested in
	// (makes the frame closable)
	public void windowClosing(WindowEvent e) {
		System.exit(0);
	}

	// But we have to override _all_ of these because
	// they're methods in the interface (what a pain)
	public void windowOpened(WindowEvent e) { }
	public void windowIconified(WindowEvent e) { }
	public void windowDeiconified(WindowEvent e) { }
	public void windowClosed(WindowEvent e) { }
	public void windowActivated(WindowEvent e) { }
	public void windowDeactivated(WindowEvent e) { }

}

(Note: This code shows how you need to close a window in a pure AWT application.)

To alleviate part of this problem, different interfaces have been made which apply to the same event type -- such as a window -- but listen for a specific category events -- such as the WindowListener, WindowFocusListener, and WindowStateListner (see p.298). None of these will aleviate the above problem, though.

A better way to deal with the above problem is to subclass an Adapter an "Adapter" is simply a class that implements an appropriate listener interface. Examples: WindowAdapter implements WindowListener, MouseAdapter implements MouseListener, KeyAdapter implements KeyListener. (Your book at the bottom of p.296 lists the Adapters.)

So, the above example can be simplified using an Adapter like so:

class MyFrame extends Frame {
	MyFrame() {
		addWindowListener(new WindowCloser());
		...
	}
	...
}

class WindowCloser extends WindowAdapter {
	public void windowClosing(WindowEvent e) {
		System.exit(0);
	}
}

This approach is best when you think you'll want to re-use your event handling code in various different places (or even different applciations).

Source code: ClosableFrame.java - An AWT app that uses the above code to make the frame closable.

#3: Use an Anonymous, Inner Class

Lastly, for those occasions where you just need a quick-and-dirty event handler and you aren't going to be reusing the code elsewhere, you can just use an anonymous, inner class, like so:

class MyFrame extends Frame {
	MyFrame() {
		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				System.exit(0);
				}
		});
		...
	}
	...
}

Explanation:

Source code: AnonInnerClass.java uses the above code to make a closable AWT frame.

Summary

Approach Frequency When you should use:
Implement Listener very often to localize event handling code
Subclass Adapter seldom to re-use event handling code between different apps / containers
Anonymous Inner Class often to localize all code for a single component

Please note that the three ways described above are basic examples that can be combined in various different ways. Many of the example programs that follow use a hybrid approach.

Action Interface (p.316)

As if that wasn't enough, the Powers That Be have given us yet another way for dealing with events. This is a somewhat different approach than any of the above methods and has more to do with activating the same command in numerous different ways, such as a toolbar button, a menu item, and a keystroke (see p.316).

The Action interface fills this role and could arguably be seen as an alternative to subclassing an Adapter. Among other things, it boasts being able to set an icon image and N number of key / value properties. It is supposed to work well with Swing apps. There is also an AbstractAction class which is similar to an Adapter.

Source Code: ActionTest.java - From your book on p.320.

The Event Zoo

AWT event hierarchy: (p.295) Shows the class hierarchy of various events

Incredibly Handy Table: (p.298) Shows all the interfaces, their methods, Event objects passed as parameters to the handlers, and what components generate them.

What follows are some examples of how to handle some of the most common events. In the course of doing this, I will (of necessity) introduce you to some of the controls described in chapter 9.

Action Events

Source code: ComboBoxTest.java from your book on p.390.

You will be handling these kind of events more than any other. (That looks like a test question.) They're generated by Buttons, ComboBoxes, Menus, Checkboxes, TextFields (and probably more).

Mouse Events

Source code: MouseTest.java from your book on p.309.

Note that this handles two different types of mouse events. Firstly, it handles "click" events, with addMouseListener() (it even uses MouseEvent.getClickCount() to see how many times the mouse was clicked). Secondly, it handles mouse moved / dragged events with addMouseMotionListener() (it also changes the cursor to a crosshair if it's over a square).

You'll also note that this examples uses a combination of the event-handling approaches described above: the event handler classes are inner (though not anonymous), one of them extends an Adapter and the other implements a Listener.

This example also shows how to use an ArrayList to keep track of a list of objects (the squares).

Key

Source code: Sketch.java - An implementation of the popular "Etch a Sketch"(C)(R)(TM) game. From your book on p.302.

Note that this example shows the difference between the keyPressed and keyTyped methods:

This example also shows how you can use isShiftDown() to test if the shift key is depressed. You can also test for the Alt key, the Control key, etc. See p.305 (middle).

This example also uses an ArrayList to keep track of a list of lines.

Focus

Source code: FocusEventExample.java - Shows how you can handle focus events.

Note that the focus handling code in the JDK has historically been some of the most buggy. See the "note" box in the middle of p.313.

Odds and Ends

Changing Look and Feel: (p.289) We talked about this last week. PlafTest.java shows how you can change the "look and feel" programatically.

Multicasting: (p.324) MulticastTest.java - shows how you can have numerous different frames all listen to the same button by instantiating one button but N event handlers.

System Event Queue: (p.326) - Shows how you can get access to the event queue used by the JVM (not the native operating system's event queue).

Custom Timer Event: (p.327) - A slightly convoluted example that shows how to make your own events. Those of you who are making a game for your application project might find this code useful.