Using a layout manager to arrange components within a container may result in a GUI that looks good, but in order to make it do anything, you have to handle events. An event typically signifies an action by the user, such as striking a key or clicking the mouse over a JButton component. But it can also refer to any other action performed by the user or the program. An event can be generated when the value of component's property changes or when a specified amount of time elapses, for example.
The event model used in Java changed between Java 1.0 and Java 1.1. The Java 1.1 event model is used by AWT and Swing in Java 1.1 and Java 1.2. The Java 1.0 event model is largely obsolete; we'll discuss it in Chapter 7, "Applets", however, since some web browsers still only support Java 1.0.
Different types of events are represented by different Java classes. The base class, from which all events inherit, is java.util.EventObject. AWT defines its own base class for GUI events, java.awt.AWTEvent, which is subclassed from EventObject. AWT then defines a number of subclasses of AWTEvent in the package java.awt.event. Swing uses many of these event types and also defines more of its own in the javax.swing.event package. Some Swing events subclass AWT events, but many subclass java.util.EventObject directly. There is one other kind of event used by Swing components: the java.beans.PropertyChangeEvent, which is part of the JavaBeans component model.
The base EventObject class defines a getSource() method that returns the object that generated or triggered the event. AWTEvent defines the getID() method; the value returned by this method is used to distinguish the various types of events that are represented by the same event class. For example, FocusEvent has two possible types: FocusEvent.FOCUS_GAINED and FocusEvent.FOCUS_LOST.
In addition to these getSource() and getID() methods, the various event subclasses define methods to return whatever data values are pertinent to the particular event type. For example, MouseEvent has getX(), getY(), and getClickCount() methods; it also inherits the getModifiers() and getWhen() methods, among others, from its superclass InputEvent. Thus, when the user clicks the mouse, you receive a MouseEvent that specifies where, when, and how many times the user clicked, along with other information, such as the set of keyboard modifier keys that were held down at the time.
An object that would like to be notified of and respond to an event is an event listener. An object that generates a particular kind of event, called an event source, maintains a list of listeners that are interested in being notified when that kind of event occurs. The event source provides methods that allow listeners to add and remove themselves from this list of interested objects. When the event source generates an event (or when a user input event such as a mouse click or a key press occurs on the event source object), the event source notifies all the listener objects that the event has occurred.
All AWT and Swing components are event sources, and all of them define (or inherit) methods for adding and removing event listeners. By convention, these methods have names that begin with "add" or "remove" and end with "Listener". So, for example, the JButton class inherits the addActionListener() and removeActionListener() methods. In the reference section of this book, you'll notice that the event registration methods of a component are grouped separately, just as the property accessor methods are. This is because one of the most important things you need to know about a component is the list of event types that it can generate.
Each type of event object typically has a corresponding event listener type. The ActionEvent event type has an ActionListener listener type, for example. Event listeners, such as ActionListener, are interfaces that extend java.util.EventListener. EventListener doesn't define any methods; it is merely a marker interface that gives all event listeners a common type. An event listener interface defines one or more methods that an event source may invoke when a particular type of event occurs. Such a method always takes an event object as its single argument. For example, the ActionListener interface defines a single method, actionPerformed(). When the user clicks on a JButton component, an ActionEvent representing that click is created and passed to the actionPerformed() method of each ActionListener object that was registered on the JButton with the addActionListener() method.
An event listener interface may define more than one method. For example, MouseListener defines several methods that correspond to different types of mouse events, including button press events and button release events. This is because MouseEvent represents several different types of mouse events. By convention, each method of an event listener is passed a single argument that is an event object of the type that corresponds to the listener. Thus, a MouseEvent object is always created when a mouse event occurs, but the object is passed to a different listener method depending on the type of mouse event that occurred.
When an event listener interface defines more than one method, it is often accompanied by an event adapter class that provides empty implementations for each of the methods. For example, the MouseListener interface defines five different methods. If your program is interested only in the mouseClicked() method, it may be easier for you to subclass the MouseAdapter class and override mouseClicked() than to implement all five methods of the MouseListener interface directly.
An important point to notice about the Java event handling model is that, in order to receive an event notification, you must implement an appropriate event listener interface. Sometimes you do this directly in your main application class. For example, an object interested in action and focus events might simply implement ActionListener and FocusListener directly.
However, it is also quite common to create special classes for the sole purpose of handling events. This is usually done with inner classes, as we saw in Example 2-1. With this event-handling paradigm, you create a simple inner class to handle each event type that you are interested in for a particular event source. Your code might look like this:
JFrame window = new JFrame("test application"); window.addFocusListener(new FocusListener() { public void focusGained(FocusEvent e) { /* gain focus code here */ } public void focusLost(FocusEvent e) { /* lose focus code here */ } });
You can also use this approach with an event adapter class, instead of an event listener interface. For example:
Panel panel = new Panel(); panel.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { /* mouse click code here */ } });
Certain types of events occur as a direct result of user input. When the user types a key or moves the mouse, for example, a KeyEvent or MouseEvent is generated. Similarly, when the user resizes a window or transfers keyboard focus to a new component, a FocusEvent or ComponentEvent is generated. These types of events represent event notifications generated by the underlying native windowing system or operating system. Other types of events, such as ActionEvent and PopupMenuEvent, do not originate in the native windowing system. Instead, these events are generated directly by AWT and Swing components.
The distinction between these types of events becomes more clear when you implement a component yourself. Consider the JButton component, for example. It receives MouseEvent events and generates ActionEvent events in response to them. For a component like this, it is not particularly appropriate or efficient to use a MouseListener object to receive mouse events.
The Java event model provides a low-level way to handle input events that originate in the underlying windowing system. When such an event occurs, it is passed to the processEvent() method of the Component on which it occurs. This method examines the type of event and invokes an appropriate method to handle the event. These methods are: processMouseEvent(), processMouseMotionEvent(), processKeyEvent(), processFocusEvent(), processComponentEvent(), and processInputMethodEvent(). By default, each method simply invokes the appropriate methods on the appropriate event listeners. When you subclass a component, however, you can override any of these protected methods to perform any other type of event handling you desire. When you override one of these methods, you should usually remember to invoke the superclass method as well, so that the appropriate event listeners are notified.
There is one additional requirement to make this low-level Java 1.1 event model work. In order to receive events of a particular type for a particular component, you must tell the component that it is interested in receiving that type of event. If you do not, events of that type are simply not delivered to the component, at least on some operating systems. With event listeners, the act of registering a listener is sufficient to tell the component what kinds of events it should request. However, when you are using the processXXXEvent() methods directly, you must first call another protected method, enableEvents(), and pass in a bit mask that specifies the types of events you are interested in. The bit mask is formed by ORing together various EVENT_MASK constants that are defined by java.awt.AWTEvent. For example:
this.enableEvents(AWTEvent.MOUSE_EVENT_MASK | AWTEvent.KEY_EVENT_MASK);
AWT and Swing define quite a few event objects, event listeners, and event adapters in the java.awt.event and javax.swing.event packages. Fortunately, all these classes and interfaces follow the same basic naming conventions. For an event X, the event object is named XEvent, the listener interface is XListener, and the adapter, if one is defined is XAdapter. The event listener interface defines methods that vary by event type, but every event listener method returns void and accepts the corresponding event object as its single argument. The only significant variation from these rules is that the java.awt.MouseListener and java.awt. MouseMotionListener listeners both work with MouseEvent events--there is no separate MouseMotionEvent.
You can find a list of the events generated by any given component by turning to its reference page and looking at the event listener registration methods for that component. Remember, too, that the component may also inherit events. Table 2-7 and Table 2-8 work in the opposite direction. For a given event listener type, these tables list the components that can generate events of that type. (Note, however, that they do not list classes that inherit events of that type.) These tables also list the names of the methods defined by each event listener interface. You can learn a lot about the intended usage of an event simply by looking at the list of listener methods to which it can be passed.
Table 2-7 shows the event listeners defined by AWT. These event types are not restricted to AWT components; Swing components use them too, as do some other Swing classes that are not components. Table 2-8 displays the event listeners defined by Swing. Note that I have also added two event listeners defined in the java.beans package, but used by Swing components, to this table.
Copyright © 2001 O'Reilly & Associates. All rights reserved.