The Java 1.1 Event Model

Now it's time to discuss the new event model that is implemented by the 1.1 release of the JDK. Although this model can seem much more complex (it does have many more pieces), it is really much simpler and more efficient. The new event model does away with the process of searching for components that are interested in an event--deliverEvent(), postEvent(), handleEvent()--and all that. The new model requires objects be registered to receive events. Then, only those objects that are registered are told when the event actually happens.

This new model is called "delegation"; it implements the Observer-Observable design pattern with events. It is important in many respects. In addition to being much more efficient, it allows for a much cleaner separation between GUI components and event handling. It is important that any object, not just a Component, can receive events. Therefore, you can separate your event-handling code from your GUI code. One set of classes can implement the user interface; another set of classes can respond to the events generated by the interface. This means that if you have designed a good interface, you can reuse it in different applications by changing the event processing. The delegation model is essential to JavaBeans, which allows interaction between Java and other platforms, like OpenDoc or ActiveX. To allow such interaction, it was essential to separate the source of an event from the recipient.[1]

[1] For more information about JavaBeans, see http://splash.javasoft.com/beans/.

The delegation model has several other important ramifications. First, event handlers no longer need to worry about whether or not they have completely dealt with an event; they do what they need to, and return. Second, events can be broadcast to multiple recipients; any number of classes can be registered to receive an event. In the old model, broadcasting was possible only in a very limited sense, if at all. An event handler could declare that it hadn't completely processed an event, thus letting its container receive the event when it was done, or an event handler could generate a new event and deliver it to some other component. In any case, developers had to plan how to deliver events to other recipients. In Java 1.1, that's no longer necessary. An event will be delivered to every object that is registered as a listener for that event, regardless of what other objects do with the event. Any listener can mark an event "consumed," so it will be ignored by the peer or (if they care) other listeners.

Finally, the 1.1 event model includes the idea of an event queue. Instead of having to override handleEvent() to see all events, you can peek into the system's event queue by using the EventQueue class. The details of this class are discussed at the end of this chapter.

In Java 1.1, each component is an event source that can generate certain types of events, which are all subclasses of AWTEvent. Objects that are interested in an event are called listeners. Each event type corresponds to a listener interface that specifies the methods that are called when the event occurs. To receive an event, an object must implement the appropriate listener interface and must be registered with the event's source, by a call to an "add listener" method of the component that generates the event. Who calls the "add listener" method can vary; it is probably the best design for the component to register any listeners for the events that it generates, but it is also possible for the event handler to register itself, or for some third object to handle registration (for example, one object could call the constructor for a component, then call the constructor for an event handler, then register the event handler as a listener for the component's events).

This sounds complicated, but it really isn't that bad. It will help to think in concrete terms. A TextField object can generate action events, which in Java 1.1 are of the class ActionEvent. Let's say we have an object of class TextActionHandler that is called myHandler that is interested in receiving action events from a text field named inputBuffer. This means that our object must implement the ActionListener interface, and this in turn, means that it must include an actionPerformed() method, which is called when an action event occurs. Now, we have to register our object's interest in action events generated by inputBuffer; to do so, we need a call to inputBuffer.addActionListener(myHandler). This call would probably be made by the object that is creating the TextField but could also be made by our event handler itself. The code might be as simple as this:

... public void init(){ ... inputBuffer = new TextField(); myHandler = new TextActionHandler(); inputBuffer.addActionListener(myHandler); // register the handler for the // buffer's events add (inputBuffer); // add the input buffer to the display ...
}

Once our object has been registered, myHandler.actionPerformed() will be called whenever a user does anything in the text field that generates an action event, like typing a carriage return. In a way, actionPerformed() is very similar to the action() method of the old event model--except that it is not tied to the Component hierarchy; it is part of an interface that can be implemented by any object that cares about events.

Of course, there are many other kinds of events. Figure 4.4 shows the event hierarchy for Java 1.1. Figure 4.5 shows the different listener interfaces, which are all subinterfaces of EventListener, along with the related adapter classes.

Figure 4.4: AWTEvent class hierarchy

[Graphic: Figure 4-4]

Figure 4.5: AWT EventListener and Adapter class hierarchies

[Graphic: Figure 4-5]

Some of the listener interfaces are constructed to deal with multiple events. For instance, the MouseListener interface declares five methods to handle different kinds of mouse events: mouse down, mouse up, click (both down and up), mouse enter, and mouse exit. Strictly speaking, this means that an object interested in mouse events must implement MouseListener and must therefore implement five methods to deal with all possible mouse actions. This sounds like a waste of the developer's effort; most of the time, you're only interested in one or two of these events. Why should you have to implement all five methods? Fortunately, you don't. The java.awt.event package also includes a set of adapter classes, which are shorthands that make it easier to write event handlers. The adapter class for any listener interface provides a null implementation of all the methods in that interface. For example, the MouseAdapter class provides stub implementations of the methods mouseEntered(), mouseExited(), mousePressed(), mouseReleased(), and mouseClicked(). If you want to write an event-handling class that deals with mouse clicks only, you can declare that your class extends MouseAdapter. It then inherits all five of these methods, and your only developing task is to override the single method you care about: mouseClicked().

A particularly convenient way to use the adapters is to write an anonymous inner class. For example, the following code deals with the MOUSE_PRESSED event without creating a separate listener class:

addMouseListener (new MouseAdapter() {
 public void mousePressed (MouseEvent e) {
 // do what's needed to handle the event System.out.println ("Clicked at: " + e.getPoint());
}
}); 

This code creates a MouseAdapter, overrides its mousePressed() method, and registers the resulting unnamed object as a listener for mouse events. Its mousePressed() method is called when MOUSE_PRESSED events occur. You can also use the adapter classes to implement something similar to a callback. For example, you could override mousePressed() to call one of your own methods, which would then be called whenever a MOUSE_PRESSED event occurs.

There are adapter classes for most of the listener interfaces; the only exceptions are the listener interfaces that contain only one method (for example, there's no ActionAdapter to go with ActionListener). When the listener interface contains only one method, an adapter class is superfluous. Event handlers may as well implement the listener interface directly, because they will have to override the only method in the interface; creating a dummy class with the interface method stubbed out doesn't accomplish anything. The different adapter classes are discussed with their related EventListener interfaces.

With all these adapter classes, listener interfaces, and event classes, it's easy to get confused. Here's a quick summary of the different pieces involved and the roles they play:

Using the 1.1 Event Model

Before jumping in and describing all the different pieces in detail, we will look at a simple applet that uses the Java 1.1 event model. Example 4.3 is equivalent to Example 4.2, except that it uses the new event model; when you press a mouse button, it just tells you what button you pressed. Notice how the new class, mouseEvent11, separates the user interface from the actual work. The class mouseEvent11 implements a very simple user interface. The class UpDownCatcher handles the events, figures out what to do, and calls some methods in mouseEvent11 to communicate the results. I added a simple interface that is called GetSetString to define the communications between the user interface and the event handler; strictly speaking, this isn't necessary, but it's a good developing practice.

Example 4.3: Handling Mouse Events in Java 1.1

// Java 1.1 only import java.awt.*; import java.awt.event.*; import java.applet.*; interface GetSetString {
 public void setString (String s);
public String getString ();
}

The UpDownCatcher class is responsible for handling events generated by the user interface. It extends MouseAdapter so that it needs to implement only the MouseListener methods that we care about (such as mousePressed() and mouseReleased()).

class UpDownCatcher extends MouseAdapter {
 GetSetString gss;
public UpDownCatcher (GetSetString s) {
 gss = s;
}

The constructor simply saves a reference to the class that is using this handler.

 public void mousePressed (MouseEvent e) {
 int mods = e.getModifiers(); if ((mods & MouseEvent.BUTTON3_MASK) != 0) {
 gss.setString ("Right Button Pressed");
}
else if ((mods & MouseEvent.BUTTON2_MASK) != 0) {
 gss.setString ("Middle Button Pressed");
}
else {
 gss.setString ("Left Button Pressed");
}
e.getComponent().repaint();
}

The mousePressed method overrides one of the methods of the MouseAdapter class. The method mousePressed() is called whenever a user presses any mouse button. This method figures out which button on a three-button mouse was pressed and calls the setString() method in the user interface to inform the user of the result.

 public void mouseReleased (MouseEvent e) {
 gss.setString ("Press a Mouse Key"); e.getComponent().repaint();
}
} 

The mouseReleased method overrides another of the methods of the MouseAdapter class. When the user releases the mouse button, it calls setString() to restore the user interface to the original message.

public class mouseEvent11 extends Applet implements GetSetString {
 private String theString = "Press a Mouse Key";
public synchronized void setString (String s) {
 theString = s;
}
public synchronized String getString () {
 return theString;
}
public synchronized void paint (Graphics g) {
 g.drawString (theString, 20, 20);
}
public void init () {
 addMouseListener (new UpDownCatcher(this));
}
} 

mouseEvent11 is a very simple applet that implements our user interface. All it does is draw the desired string on the screen; the event handler tells it what string to draw. The init() method creates an instance of the event handler, which is UpDownCatcher, and registers it as interested in mouse events.

Because the user interface and the event processing are in separate classes, it would be easy to use this user interface for another purpose. You would have to replace only the UpDownCatcher class with something else--perhaps a more complex class that reported when the mouse entered and exited the area.

AWTEvent and Its Children

Under the 1.1 delegation event model, all system events are instances of AWTEvent or its subclasses. The model provides two sets of event types. The first set are fairly raw events, such as those indicating when a component gets focus, a key is pressed, or the mouse is moved. These events exist in ComponentEvent and its subclasses, along with some new events previously available only by overriding non-event-related methods. In addition, higher-level event types (for example, selecting a button) are encapsulated in other subclasses of AWTEvent that are not children of ComponentEvent.

AWTEvent

Variables Constants

The constants of AWTEvent are used in conjunction with the internal method Component.eventEnabled(). They are used to help the program determine what style of event handling (true/false--containment or listening--delegation) the program uses and which events a component processes. If you want to process 1.1 events without providing a listener, you need to set the mask for the type of event you want to receive. Look in Components, for more information on the use of these constants:

public final static long ACTION_EVENT_MASK
public final static long ADJUSTMENT_EVENT_MASK
public final static long COMPONENT_EVENT_MASK
public final static long CONTAINER_EVENT_MASK
public final static long FOCUS_EVENT_MASK
public final static long ITEM_EVENT_MASK
public final static long KEY_EVENT_MASK
public final static long MOUSE_EVENT_MASK
public final static long MOUSE_MOTION_EVENT_MASK
public final static long TEXT_EVENT_MASK
public final static long WINDOW_EVENT_MASK

In addition to the mask constants, the constant RESERVED_ID_MAX is the largest event ID reserved for "official" events. You may use ID numbers greater than this value to create your own events, without risk of conflicting with standard events.

public final static long RESERVED_ID_MAXConstructors

Since AWTEvent is an abstract class, you cannot call the constructors directly. They are automatically called when an instance of a child class is created.

Methods
java.awt.event.MouseEvent[MOUSE_RELEASED,(69,107),mods=0,clickCount=1] on panel1 

ComponentEvent

Constants Constructors Methods
java.awt.event.ComponentEvent[COMPONENT_RESIZED (0, 0, 100x100)] on button0 

ContainerEvent

The ContainerEvent class includes events that result from specific container operations. Constants

Constructors Methods

FocusEvent

The FocusEvent class contains the events that are generated when a component gets or loses focus. These may be either temporary or permanent focus changes. A temporary focus change is the result of something else happening, like a window appearing in front of you. Once the window is removed, focus is restored. A permanent focus change is usually the result of focus traversal, using the keyboard or the mouse: for example, you clicked in a text field to type in it, or used Tab to move to the next component. More programmatically, permanent focus changes are the result of calls to Component.requestFocus(). Constants

Constructors Methods

WindowEvent

The WindowEvent class encapsulates the window-oriented events. Constants

NOTE:

If there is a call to System.exit() in the windowClosing() listener, the window will not be around to call windowClosed(), nor will other listeners know.

Constructors Methods
java.awt.event.WindowEvent[WINDOW_CLOSING] on frame0 

PaintEvent

The PaintEvent class encapsulates the paint-oriented events. There is no corresponding PaintListener class, so you cannot listen for these events. To process them, override the paint() and update() routines of Component. The PaintEvent class exists to ensure that events are serialized properly through the event queue. Constants

Constructors Methods
java.awt.event.PaintEvent[PAINT,updateRect=java.awt.Rectangle[x=0,y=0, width=192,height=173]] on frame0 

InputEvent

The InputEvent class provides the basis for the key and mouse input and movement routines. KeyEvent and MouseEvent provide the specifics of each. Constants

The constants of InputEvent help identify which modifiers are present when an input event occurs, as shown in Example 4.3. To examine the event modifiers and test for the presence of these masks, call getModifiers() to get the current set of modifiers.

Constructors

InputEvent is an abstract class with no public constructors. Methods

Unlike the Event class, InputEvent has an isAltDown() method to check the ALT_MASK setting.

if ((ie.getModifiers() & MouseEvent.META_MASK) != 0) {
 System.out.println ("Meta is set");
}
Date d = new Date (ie.getWhen()); 

KeyEvent

The KeyEvent class is a subclass of InputEvent for dealing with keyboard events. There are two fundamental key actions: key presses and key releases. These are represented by KEY_PRESSED and KEY_RELEASED events. Of course, it's inconvenient to think in terms of all these individual actions, so Java also keeps track of the "logical" keys you type. These are represented by KEY_TYPED events. For every keyboard key pressed, a KeyEvent.KEY_PRESSED event occurs; the key that was pressed is identified by one of the virtual keycodes from Table 4.4 and is available through the getKeyCode() method. For example, if you type an uppercase A, you will get two KEY_PRESSED events, one for shift (VK_SHIFT) and one for the "a" (VK_A). You will also get two KeyEvent.KEY_RELEASED events. However, there will only be one KeyEvent.KEY_TYPED event; if you call getKeyChar() for the KEY_TYPED event, the result will be the Unicode character "A" (type char). KEY_TYPED events do not happen for action-oriented keys like function keys. Constants

Like the Event class, numerous constants help you identify all the keyboard keys. Table 4.4 shows the constants that refer to these keyboard keys. The values are all declared public static final int. A few keys represent ASCII characters that have string equivalents like \n.

Key Constants in Java 1.1
VK_ENTER VK_0 VK_A VK_F1 VK_ACCEPT
VK_BACK_SPACE VK_1 VK_B VK_F2 VK_CONVERT
VK_TAB VK_2 VK_C VK_F3 VK_FINAL
VK_CANCEL VK_3 VK_D VK_F4 VK_KANA
VK_CLEAR VK_4 VK_E VK_F5 VK_KANJI
VK_SHIFT VK_5 VK_F VK_F6 VK_MODECHANGE
VK_CONTROL VK_6 VK_G VK_F7 VK_NONCONVERT
VK_ALT VK_7 VK_H VK_F8
VK_PAUSE VK_8 VK_I VK_F9
VK_CAPS_LOCK VK_9 VK_J VK_F10
VK_ESCAPE VK_NUMPAD0 VK_K VK_F11
VK_SPACE VK_NUMPAD1 VK_L VK_F12
VK_PAGE_UP VK_NUMPAD2 VK_M VK_DELETE
VK_PAGE_DOWN VK_NUMPAD3 VK_N VK_NUM_LOCK
VK_END VK_NUMPAD4 VK_O VK_SCROLL_LOCK
VK_HOME VK_NUMPAD5 VK_P VK_PRINTSCREEN
VK_LEFT VK_NUMPAD6 VK_Q VK_INSERT
VK_UP VK_NUMPAD7 VK_R VK_HELP
VK_RIGHT VK_NUMPAD8 VK_S VK_META
VK_DOWN VK_NUMPAD9 VK_T VK_BACK_QUOTE
VK_COMMA VK_MULTIPLY VK_U VK_QUOTE
VK_PERIOD VK_ADD VK_V VK_OPEN_BRACKET
VK_SLASH VK_SEPARATER[1] VK_W VK_CLOSE_BRACKET
VK_SEMICOLON VK_SUBTRACT VK_X
VK_EQUALS VK_DECIMAL VK_Y
VK_BACK_SLASH VK_DIVIDE VK_Z

Footnotes:

[1] Expect VK_SEPARATOR to be added at some future point. This constant represents the numeric separator key on your keyboard.

Other constants identify what the user did with a key.

Constructors Methods
Key Text Properties
Property Default Property Default
AWT.accept Accept AWT.f8
AWT.add NumPad + AWT.f9
AWT.alt Alt AWT.help Help
AWT.backQuote Back Quote AWT.home Home
AWT.backSpace Backspace AWT.insert Insert
AWT.cancel Cancel AWT.kana Kana
AWT.capsLock Caps Lock AWT.kanji Kanji
AWT.clear Clear AWT.left Left
AWT.control Control AWT.meta Meta
AWT.decimal NumPad . AWT.modechange Mode Change
AWT.delete Delete AWT.multiply NumPad *
AWT.divide NumPad / AWT.noconvert No Convert
AWT.down Down AWT.numLock Num Lock
AWT.end End AWT.numpad NumPad
AWT.enter Enter AWT.pause Pause
AWT.escape Escape AWT.pgdn Page Down
AWT.final Final AWT.pgup Page Up
AWT.f1 AWT.printScreen Print Screen
AWT.f10 AWT.quote Quote
AWT.f11 AWT.right Right
AWT.f12 AWT.scrollLock Scroll Lock
AWT.f2 AWT.separator NumPad ,
AWT.f3 AWT.shift Shift
AWT.f4 AWT.space Space
AWT.f5 AWT.subtract NumPad -
AWT.f6 AWT.tab Tab
AWT.f7 AWT.unknown Unknown keyCode
AWT.up Up
Key Modifiers Text Properties
Property Default
AWT.alt Alt
AWT.control Ctrl
AWT.meta Meta
AWT.shift Shift
java.awt.event.KeyEvent[KEY_PRESSED,keyCode=118, F7,modifiers=Ctrl+Shift] on textfield0 

MouseEvent

The MouseEvent class is a subclass of InputEvent for dealing with mouse events. Constants

Constructors Methods
public void processMouseEvent(MouseEvent e) {
 if (e.isPopupTrigger()) aPopup.show(e.getComponent(), e.getX(), e.getY()); super.processMouseEvent(e);
}
java.awt.event.MouseEvent[MOUSE_PRESSED,(5,7),mods=0,clickCount=2] on textfield0 

ActionEvent

The ActionEvent class is the first higher-level event class. It encapsulates events that signify that the user is doing something with a component. When the user selects a button, list item, or menu item, or presses the Return key in a text field, an ActionEvent passes through the event queue looking for listeners. Constants

Constructors Methods
java.awt.event.ActionEvent[ACTION_PERFORMED,cmd=Help] on button0 

AdjustmentEvent

The AdjustmentEvent class is another higher-level event class. It encapsulates events that represent scrollbar motions. When the user moves the slider of a scrollbar or scroll pane, an AdjustmentEvent passes through the event queue looking for listeners. Although there is only one type of adjustment event, there are five subtypes represented by constants UNIT_DECREMENT, UNIT_INCREMENT, and so on. Constants

Constructors Methods
java.awt.event.AdjustableEvent[ADJUSTMENT_VALUE_CHANGED, adjType=TRACK,value=27] on scrollbar0 

ItemEvent

The ItemEvent class is another higher-level event class. It encapsulates events that occur when the user selects a component, like ActionEvent. When the user selects a checkbox, choice, list item, or checkbox menu item, an ItemEvent passes through the event queue looking for listeners. Although there is only one type of ItemEvent, there are two subtypes represented by the constants SELECTED and DESELECTED. Constants

Constructors Methods
java.awt.event.ItemEvent[ITEM_STATE_CHANGED,item=Help, stateChange=SELECTED] on checkbox1 

TextEvent

The TextEvent class is yet another higher-level event class. It encapsulates events that occur when the contents of a TextComponent have changed, although is not required to have a TextComponent source. When the contents change, either programmatically by a call to setText() or because the user typed something, a TextEvent passes through the event queue looking for listeners. Constants

Constructors Method

Event Listener Interfaces and Adapters

Java 1.1 has 11 event listener interfaces, which specify the methods a class must implement to receive different kinds of events. For example, the ActionListener interface defines the single method that is called when an ActionEvent occurs. These interfaces replace the various event-handling methods of Java 1.0: action() is now the actionPerformed() method of the ActionListener interface, mouseUp() is now the mouseReleased() method of the MouseListener interface, and so on. Most of the listener interfaces have a corresponding adapter class, which is an abstract class that provides a null implementation of all the methods in the interface. (Although an adapter class has no abstract methods, it is declared abstract to remind you that it must be subclassed.) Rather than implementing a listener interface directly, you have the option of extending an adapter class and overriding only the methods you care about. (Much more complex adapters are possible, but the adapters supplied with AWT are very simple.) The adapters are available for the listener interfaces with multiple methods. (If there is only one method in the listener interface, there is no need for an adapter.)

This section describes Java 1.1's listener interfaces and adapter classes. It's worth noting here that Java 1.1 does not allow you to modify the original event when you're writing an event handler.

ActionListener

The ActionListener interface contains the one method that is called when an ActionEvent occurs. It has no adapter class. For an object to listen for action events, it is necessary to call the addActionListener() method with the class that implements the ActionListener interface as the parameter. The method addActionListener() is implemented by Button, List, MenuItem, and TextField components. Other components don't generate action events.

AdjustmentListener

The AdjustmentListener interface contains the one method that is called when an AdjustmentEvent occurs. It has no adapter class. For an object to listen for adjustment events, it is necessary to call addAdjustmentListener() with the class that implements the AdjustmentListener interface as the parameter. The addAdjustmentListener() method is implemented by the Scrollbar component and the Adjustable interface. Other components don't generate adjustment events.

ComponentListener and ComponentAdapter

The ComponentListener interface contains four methods that are called when a ComponentEvent occurs; component events are used for general actions on components, like moving or resizing a component. The adapter class corresponding to ComponentListener is ComponentAdapter. If you care only about one or two of the methods in ComponentListener, you can subclass the adapter and override only the methods that you are interested in. For an object to listen for component events, it is necessary to call Component.addComponentListener() with the class that implements the interface as the parameter.

ContainerListener and ContainerAdapter

The ContainerListener interface contains two methods that are called when a ContainerEvent occurs; container events are generated when components are added to or removed from a container. The adapter class for ContainerListener is ContainerAdapter. If you care only about one of the two methods in ContainerListener, you can subclass the adapter and override only the method that you are interested in. For a container to listen for container events, it is necessary to call Container.addContainerListener() with the class that implements the interface as the parameter.

FocusListener and FocusAdapter

The FocusListener interface has two methods, which are called when a FocusEvent occurs. Its adapter class is FocusAdapter. If you care only about one of the methods, you can subclass the adapter and override the method you are interested in. For an object to listen for a FocusEvent, it is necessary to call the Component.addFocusListener() method with the class that implements the FocusListener interface as the parameter.

ItemListener

The ItemListener interface contains the one method that is called when an ItemEvent occurs. It has no adapter class. For an object to listen for an ItemEvent, it is necessary to call addItemListener() with the class that implements the ItemListener interface as the parameter. The addItemListener() method is implemented by the Checkbox, CheckboxMenuItem, Choice, and List components. Other components don't generate item events.

KeyListener and KeyAdapter

The KeyListener interface contains three methods that are called when a KeyEvent occurs; key events are generated when the user presses or releases keys. The adapter class for KeyListener is KeyAdapter. If you only care about one or two of the methods in KeyListener, you can subclass the adapter and only override the methods that you are interested in. For an object to listen for key events, it is necessary to call Component.addKeyListener() with the class that implements the interface as the parameter.

MouseListener and MouseAdapter

The MouseListener interface contains five methods that are called when a nonmotion oriented MouseEvent occurs; mouse events are generated when the user presses or releases a mouse button. (Separate classes, MouseMotionListener and MouseMotionAdapter, are used to handle mouse motion events; this means that you can listen for mouse clicks only, without being bothered by thousands of mouse motion events.) The adapter class for MouseListener is MouseAdapter. If you care about only one or two of the methods in MouseListener, you can subclass the adapter and override only the methods that you are interested in. For an object to listen for mouse events, it is necessary to call the method Window.addWindowListener() with the class that implements the interface as the parameter.

MouseMotionListener and MouseMotionAdapter

The MouseMotionListener interface contains two methods that are called when a motion-oriented MouseEvent occurs; mouse motion events are generated when the user moves the mouse, whether or not a button is pressed. (Separate classes, MouseListener and MouseAdapter, are used to handle mouse clicks and entering/exiting components. This makes it easy to ignore mouse motion events, which are very frequent and can hurt performance. You should listen only for mouse motion events if you specifically need them.) MouseMotionAdapter is the adapter class for MouseMotionListener. If you care about only one of the methods in MouseMotionListener, you can subclass the adapter and override only the method that you are interested in. For an object to listen for mouse motion events, it is necessary to call Component.addMouseMotionListener() with the class that implements the interface as the parameter.

TextListener

The TextListener interface contains the one method that is called when a TextEvent occurs. It has no adapter class. For an object to listen for a TextEvent, it is necessary to call addTextListener() with the class that implements the TextListener interface as the parameter. The addTextListener() method is implemented by the TextComponent class, and thus the TextField and TextArea components. Other components don't generate text events.

WindowListener and WindowAdapter

The WindowListener interface contains seven methods that are called when a WindowEvent occurs; window events are generated when something changes the visibility or status of a window. The adapter class for WindowListener is WindowAdapter. If you care about only one or two of the methods in WindowListener, you can subclass the adapter and override only the methods that you are interested in. For an object to listen for window events, it is necessary to call the method Window.addWindowListener() or Dialog.addWindowListener() with the class that implements the interface as the parameter.

AWTEventMulticaster

The AWTEventMulticaster class is used by AWT to manage the listener queues for the different events, and for sending events to all interested listeners when they occur (multicasting). Ordinarily, you have no need to work with this class or know about its existence. However, if you wish to create your own components that have their own set of listeners, you can use the class instead of implementing your own event-delivery system. See "Constructor methods" in this section for more on how to use the AWTEventMulticaster.

AWTEventMulticaster looks like a strange beast, and to some extent, it is. It contains methods to add and remove every possible kind of listener and implements all of the listener interfaces (11 as of Java 1.1). Because it implements all the listener interfaces, you can pass an event multicaster as an argument wherever you expect any kind of listener. However, unlike a class you might implement to listen for a specific kind of event, the multicaster includes machinery for maintaining chains of listeners. This explains the rather odd signatures for the add() and remove() methods. Let's look at one in particular:

public static ActionListener add(ActionListener first, ActionListener second) 

This method takes two ActionListeners and returns another ActionListener. The returned listener is actually an event multicaster that contains the two listeners given as arguments in a linked list. However, because it implements the ActionListener interface, it is just as much an ActionListener as any class you might write; the fact that it contains two (or more) listeners inside it is irrelevant. Furthermore, both arguments can also be event multicasters, containing arbitrarily long chains of action listeners; in this case, the returned listener combines the two chains. Most often, you will use add to add a single listener to a chain that you're building, like this:

actionListenerChain=AWTEventMulticaster.add(actionListenerChain, newActionListener); 

actionListenerChain is an ActionListener--but it is also a multicaster holding a chain of action listeners. To start a chain, use null for the first argument. You rarely need to call the AWTEventMulticaster constructor. add() is a static method, so you can use it with either argument set to null to start the chain.

Now that you can maintain chains of listeners, how do you use them? Simple; just deliver your event to the appropriate method in the chain. The multicaster takes care of sending the event to all the listeners it contains:

actionListenerChain.actionPerformed(new ActionEvent(...)); 
Variables Constructor methods Listener methods

These methods implement all of the listener interfaces. Rather than repeating all the descriptions, the methods are just listed.

Support methods

There is an add() method for every listener interface. Again, I've listed them with a single description.

Again, there are remove() methods for every listener type, and I've economized on the descriptions.

Using an event multicaster

Example 4.4 shows how to use AWTEventMulticaster to create a component that generates ItemEvents. The AWTEventMulticaster is used in the addItemListener() and removeItemListener() methods. When it comes time to generate the event in processEvent(), the itemStateChanged() method is called to notify anyone who might be interested. The item event is generated when a mouse button is clicked; we just count the number of clicks to determine whether an item was selected or deselected. Since we do not have any mouse listeners, we need to enable mouse events with enableEvents() in the constructor, as shown in the following example.

Example 4.4: Using an AWTEventMulticaster

// Java 1.1 only import java.awt.*; import java.awt.event.*; class ItemEventComponent extends Component implements ItemSelectable {
 boolean selected; int i = 0; ItemListener itemListener = null; ItemEventComponent () {
 enableEvents (AWTEvent.MOUSE_EVENT_MASK);
}
public Object[] getSelectedObjects() {
 Object o[] = new Object[1]; o[0] = new Integer (i);
return o;
}
public void addItemListener (ItemListener l) {
 itemListener = AWTEventMulticaster.add (itemListener, l);
}
public void removeItemListener (ItemListener l) {
 itemListener = AWTEventMulticaster.remove (itemListener, l);
}
public void processEvent (AWTEvent e) {
 if (e.getID() == MouseEvent.MOUSE_PRESSED) {
 if (itemListener != null) {
 selected = !selected; i++; itemListener.itemStateChanged ( new ItemEvent (this, ItemEvent.ITEM_STATE_CHANGED, getSelectedObjects(), (selected?ItemEvent.SELECTED:ItemEvent.DESELECTED)));
}
}
}
}
public class ItemFrame extends Frame implements ItemListener {
 ItemFrame () {
 super ("Listening In"); ItemEventComponent c = new ItemEventComponent (); add (c, "Center"); c.addItemListener (this); c.setBackground (SystemColor.control); setSize (200, 200);
}
public void itemStateChanged (ItemEvent e) {
 Object[] o = e.getItemSelectable().getSelectedObjects(); Integer i = (Integer)o[0]; System.out.println (i);
}
public static void main (String args[]) {
 ItemFrame f = new ItemFrame(); f.show();
}
} 

The ItemFrame displays just an ItemEventComponent and listens for its item events.

The EventQueue class lets you manage Java 1.1 events directly. You don't usually need to manage events yourself; the system takes care of event delivery behind the scene. However, should you need to, you can acquire the system's event queue by calling Toolkit.getSystemEventQueue(), peek into the event queue by calling peekEvent(), or post new events by calling postEvent(). All of these operations may be restricted by the SecurityManager. You should not remove the events from the queue (i.e., don't call getNextEvent()) unless you really mean to.Constructors

Methods