Events can be generated many ways, but are often generated by the user through an input device such as a mouse or keyboard. Events can be divided into two groups: low-level and semantic. Low-level events represent window-system occurrences or low-level input, such as the pressing of a mouse button or the typing of the letter ‘a’. Semantic events include anything else like the selection of a menu or the resizing of a window, and they may or may not be triggered by user input. Generally speaking, semantic events are the ones to pay attention to because they represent more “meaningful” concepts.
All event classes extend from the EventObject base class which extends directly from Object as shown in figure 13-1.
java.lang.Object java.util.EventObject
This chapter will deal exclusively with events that are triggered by user actions, but EventObjects are not limited to representing user actions. They may represent any programmer-defined event. EventObject’s one and only constructor requires a non-null object considered to be the source of the event. In this chapter, the source object will always be a GUI component such as “the button the user clicked” or “the field in which the user typed”. In general, it may be absolutely any object so long as that object can be considered the source (however the programmer chooses to define it) of the event. Table 13-1 lists and describes the significant EventObject methods.
Method Name and Purpose |
---|
public Object getSource() Returns the source of the event. |
Events defined by the Java API all follow the naming convention <XXX>Event where <XXX> uniquely identifies the type of event. There are very many subclasses of EventObject. The ones with which we will become acquainted in this chapter are ActionEvent, MouseEvent, KeyEvent, ChangeEvent and ListSelectionEvent, but the process for handling events is much the same whatever event type you need to handle.
Event listeners are classes that the programmer writes and registers with a component. Event listeners extend from the java.util.EventListener interface, which is a “tagging” interface declaring no methods of its own. For every event type, there is an event listener interface that extends EventListener and defines whatever methods are appropriate to that particular event type. By convention, each method of an event listener interface is passed an EventObject parameter that encapsulates details specific to the event that caused the method to be called. The programmer must implement these EventListener methods to realize whatever application behavior he wants.
In general, event listeners follow the naming convention <XXX>Listener where <XXX> corresponds to the particular event type listened for. The event listeners with which we will become acquainted in this chapter include ActionListener, MouseListener, MouseMotionListener, MouseWheelListener, KeyListener, ChangeListener and ListSelectionListener.
A component may have any number of registered event listeners, and it provides methods for managing them. Registration methods follow the naming convention add <XXX> Listener where <XXX> Listener is the type of the EventListener parameter. Methods for unregistering specific listener types are named remove <XXX> Listener, and methods for retrieving an array of all the listeners of a type are named get <XXX> Listeners. java.awt.Component also provides a generic method named getListeners, to which you pass a listener-class parameter to receive an array of listeners of the specified type. Table 13-2 lists Component’s EventListener management methods.
Method Name and Purpose |
---|
public void add<XXX>Listener(<XXX>Listener instance) Register a listener with a component. |
public void remove<XXX>Listener(<XXX>Listener instance) Remove a listener from the component’s registered listeners. |
<XXX>Listener[] get<XXX>Listeners() Get all the listeners of a certain type. |
EventListener[] getListeners(<XXX>Listener class) Get all the listeners of the specified type. |
Often, the best way to see what events a component can respond to is to look through that component’s API for method names beginning with the word “add” and ending with the word “Listener”. Remember to consider methods that the component inherits as well as the ones it defines! This will point you to the event listeners that the component handles. Then, if you look at the API for each different event listener you will see one or more methods that take an EventObject parameter. The particular type of this EventObject parameter will be a type of event to which the component can respond. As an example, table 13-3 lists the various registration methods offered by JButton and their associated event listener types and event types. JButton can respond to all of these event types. In some cases there is more that one event listener type for a given event type. We will explore this many-to-one relationship a bit when we handle MouseEvents later.
Registration Method | EventListener Parameter | EventObject Type |
---|---|---|
addActionListener() | ActionListener | ActionEvent |
addChangeListener() | ChangeListener | ChangeEvent |
addItemListener() | ItemListener | ItemEvent |
addAncestorListener() | AncestorListener | AncestorEvent |
addPropertyChangeListener() | PropertyChangeListener | PropertyChangeEvent |
addVetoableChangeListener() | VetoableChangeListener | PropertyChangeEvent |
addContainerListener() | ContainerListener | ContainerEvent |
addComponentListener() | ComponentListener | ComponentEvent |
addFocusListener() | FocusListener | FocusEvent |
addHierarchyBoundsListener() | HierarchyBoundsListener | HierarchyEvent |
addHierarchyListener() | HierarchyListener | HierarchyEvent |
addInputMethodListener() | InputMethodListener | InputMethodEvent |
addKeyListener() | KeyListener | KeyEvent |
addMouseListener() | MouseListener | MouseEvent |
addMouseMotionListener() | MouseMotionListener | MouseEvent |
addMouseWheelListener() | MouseWheelListener | MouseEvent |
Making an application respond to user input is as simple as linking events to listeners, but choosing the correct event to listen for is not always as obvious as you might wish. Let’s take the prototypical case of an “OK” button in a dialog as shown in figure 13-2. To make the button functional, one might reason (naively) that you need to trap a MouseEvent with a MouseListener because buttons are “clicked” with a mouse. This indeed would allow the button to respond to mouse clicks but the button would only be partially functional. Being an “OK” button in a Dialog, the press of the “Enter” key should also trigger the button. One might reason (again naively) that you could also write a KeyListener that listens for key events, figures out if the enter-key was pressed and then does the same thing that the MouseListener did. That would help, but this approach would be missing the big picture. What if five years from now users of the “Acme Palm-Top Telephonic Device” running the “Acme Java-Enabled Operating System” will only be able to trigger buttons by speaking the button’s name into the mouthpiece of a telephone? (I made this up but it is plausible!). A button written today with MouseListeners and KeyListeners would be broken five years from now on this future system.
Figure 13-2: ACME Product Services Confirmation
So, what does it really mean to make this button fully “functional”? Should we have to worry about keeping up with the myriad platform/operating systems now and in the future in a continual effort to keep it working? The answer is an emphatic NO! Someone, of course, must do that work, but not you, the Java programmer. It is the responsibility and hard work of the developers at Sun Microsystems and elsewhere who port Java to the various platforms and operating systems to make sure that each java port conforms to the target platform’s own rules. In this very typical case, we shouldn’t be interested how the button was invoked; we just need to know that it was invoked. Therefore, rather than listening for low-level events like mouse-clicks and key-presses which are inherently bound to particular methods of invocation, we should listen for a semantic event that corresponds to “invoking” a button. Is there such an event type? Yes. Thanks to the untiring efforts of the developers at Sun Microsystems, there is a semantic event that encapsulates any input mechanism (mouse, key, voice, etc) now and in the future for triggering a button as appropriate for each different platform. Please take the time now to study Figure 13-3 which illustrates the event-handling process as it relates to our “OK” button. As the figure illustrates, the event type that covers all methods of invoking this button would be the ActionEvent. We will discuss ActionEvent soon.
Figure 13-3: Event-Handling Division of Labor
As you can see, while the process for making an application interactive is simple in concept, it pays to know what the API provides when deciding which event type to handle.
Handling GUI events in a Swing application is all about linking events to listeners. Events can be generated many ways but are often generated by the user through an input device such as a mouse or keyboard. The base event class is EventObject. Event listeners “listen” or wait for specific events on specific objects and execute whatever code the application developer has written. The base listener class is EventListener. To leverage the power of the API and make your code as robust and portable as possible, you should listen for semantic events rather than low-level events whenever possible.