Event Listeners

advertisement
10. Events
Objectives
This chapter covers aspects of the following Java certification exam
objective:
• Write code to implement listener classes and methods, and in listener
methods, extract information from the event to determine the affected
component, mouse position, nature, and time of the event. State the event
classname for any specified event listener interface in the java.awt.event
package.
Java's original "outward rippling" event model proved to have some shortcomings. A new "event delegation" model was introduced in release 1.1 of
the JDK. Both models are supported in Java 2, but eventually the old model
will disappear. For now, all methods that support the old event model are
deprecated.
The two models are mutually incompatible. A Java program that uses both
models is likely to fail, with events being lost or incorrectly processed.
This chapter reviews the new model in detail.
Motivation for the Event Delegation Model
Certain flaws in the original event model became apparent after Java had
been in the world long enough for large programs to be developed. The
major problem was that an event could only be handled by the component
that originated the event or by one of the containers that contained the
originating component. This restriction violated one of the fundamental
principles of object-oriented programming: functionality should reside in the
most appropriate class. Often the most appropriate class for handling an
event is not a member of the originating component's containment hierarchy.
Another drawback of the original model was that a large number of CPU
cycles were wasted on uninteresting events. Any event in which a program
had no interest would ripple all the way through the containment hierarchy
before eventually being discarded. The original event model provided no way
to disable processing of irrelevant events.
In the event delegation model, a component may be told which object or
objects should be notified when the component generates a particular kind of
event. If a component is not interested in an event type, then events of that
type will not be propagated.
The delegation model is based on four concepts:
•
•
•
•
Event classes
Event listeners
Explicit event enabling
Adapters
This chapter explains each of these concepts in turn.
The Event Class Hierarchy
The event delegation model defines a large number of new event classes.
The hierarchy of event classes that you need to know for the exam is shown
in Figure 10.1. Most of the event classes reside in the java.awt.event
package.
The topmost superclass of all the new event classes is
java.util.EventObject. It is a very general class, with only one method of
interest:

Object getSource(): returns the object that originated the event
One subclass of EventObject is java.awt.AWTEvent, which is the
superclass of all the delegation model event classes. Again, there is only one
method of interest:

int getlD(): returns the ID of the event
An event's ID is an int that specifies the exact nature of the event. For
example, an instance of the MouseEvent class can represent one of seven
occurrences: a click, a drag, an entrance, an exit, a move, a press, or a
release.
FIGURE 10.1
Event class hierarchy
java.util.EventObject
java.awt.AWTEvent
ActionEvent AdjustmentEvent ComponentEvent ItemEvent
TextEvent
ContainerEvent FocusEvent InputEvent PaintEvent WindowEvent
KeyEvent MouseEvent
All classes belong to java.awt.event package unless otherwise noted.
Each of these possibilities is represented by an int:
MouseEvent.MOUSE_CLICKED, MouseEvent.MOUSE_DRAGGED, and so
on.
The subclasses of java.awt.AWTEvent represent the various event type
that can be generated by the various AWT components. These event types
are:

ActionEvent: generated by activation of components

AdjustmentEvent: generated by adjustment of adjustable
component such as scroll bars

ContainerEvent: generated when components are added to or
removed from a container

FocusEvent: generated when a component receives or loses input
focus

ItemEvent: generated when an item is selected from a list, choice, or
check box

KeyEvent: generated by keyboard activity

MouseEvent: generated by mouse activity

PaintEvent: generated when a component is painted

TextEvent: generated when a text component is modified

WindowEvent: generated by window activity (such as iconifying or
de-iconifying)
The InputEvent superclass has a getWhen() method that returns the time
when the event took place; the return type is long. The MouseEvent class
has getX() and getY() methods that return the position of the mouse within
the originating component at the time the event took place; the return types
are both int.
There are two ways to handle the events listed previously. The first way is to
delegate event handling to a listener object. The second way is to explicitly
enable the originating component to handle its own events. These two
strategies are discussed in the next two sections.
Event Listeners
An event listener is an object to which a component has delegated the task
of handling a particular kind of event. When the component experiences
input, an event of the appropriate type is constructed; the event is then
passed as the parameter to a method call on the listener. A listener must
implement the interface that contains the event-handling method.
For example, consider a button in an applet. When the button is clicked, an
action event is to be sent to an instance of class MyActionListener. The code
for MyActionListener is as follows:
1. class MyActionListener implements ActionListener {
2.
public void actionPerformed( ActionEvent ae ) {
3.
System.out.println( "Action performed." );
4.
}
5. }
The class implements the ActionListener interface, thus guaranteeing the
presence of an actionPerformed() method. The applet code looks like this:
1. public class ListenerTest extends Applet {
2.
public void init() {
3.
Button btn = new Button( "OK" );
4.
MyActionListener listener = new MyActionListener();
5.
btn.addActionListener( listener );
6.
add( btn );
7.
}
8. }
On line 4, an instance of MyActionListener is created. On line 5, this instance
is set as one of the button's action listeners. The code follows a standard
formula for giving an action listener to a component; the formula can be
summarized as follows:
1.
2.
3.
4.
Create a listener class that implements the ActionListener interface.
Construct the component.
Construct an instance of the listener class.
Call addActionListener() on the component, passing in the listener object.
In all, there are 11 listener types, each represented by an interface. Table
10.1 lists the listener interfaces, along with the interface methods and the
addXXXListenerQ methods.
TABLE
10.1:
Listener interfaces
Interface
Interface Methods
Add Method
ActionListener
AdjustmentListener
ComponentListener
actionPerformed( ActionEvent )
adjustmentValueChanged( AdjustmentEvent )
addActionListener() addAdjustmentListener()
ContainerListener
componentHidden( ComponentEvent )
addComponentlistener()
componentMoved( ComponentEvent )
componentResized( ComponentEvent )
componentShown( ComponentEvent )
componentAdded( ContainerEvent )
addContainerListener()
componentRemoved( ContainerEvent )
ItemListener KeyListener
MouseListener
FocusListener
focusGained( FocusEvent )
focusLost( FocusEvent ) itemStateChanged( ItemEvent )
keyPressed( KeyEvent ) keyReleased( KeyEvent ) keyTyped( KeyEvent )
mousedClicked( MouseEvent ) mouseEntered( MouseEvent ) mouseExited(
MouseEvent ) mousePressed( MouseEvent ) mouseReleased( MouseEvent
)
MouseMotionListener mouseDragged( MouseEvent )
mouseMoved( MouseEvent ) textValueChanged( TextEvent )
windowActivated( WindowEvent ) windowClosed( WindowEvent )
windowClosing( WindowEvent ) windowDeactivated( WindowEvent )
windowDeiconified( WindowEvent ) windowlconified( WindowEvent )
windowOpened( WindowEvent )
TextListener WindowListener
addFocusListener()
addItemListener() addKeyListener()
addMouseListener()
addMouseMotionListener()
addTextListener() addWindowListener()
A component may have multiple listeners for any event type. There is no
guarantee that listeners will be notified in the order in which they were
added. There is also no guarantee that all listener notification will occur in
the same thread; thus listeners must take precautions against corrupting
shared data.
An event listener may be removed from a component's list of listeners by
calling a removeXXXListener() method, passing in the listener to be
removed. For example, the code below removes action listener al from
button btn:
btn.removeActionListener( al );
The techniques described in this section represent the standard way to
handle events in the delegation model. Event delegation is sufficient in most
situations; however, there are times when it is preferable for a component to
handle its own events, rather than delegating its events to listeners.
The next section describes how to make a component handle its own events.
Explicit Event Enabling
There is an alternative to delegating a component's events. It is possible to
subclass the component and override the method that receives events and
dispatches them to listeners. For example, components that originate action
events have a method called processActionEvent( ActionEvent ), which
dispatches its action event to each action listener.
The following code implements a subclass of Button that overrides
processActionEvent():
1. class MyBtn extends Button {
2.
public MyBtn( String label ) {
3.
super( label );
4.
enableEvents( AWTEvent.ACTION_EVENT_MASK );
5.
}
6.
7.
public void processActionEvent( ActionEvent ae ) {
8.
System.out.println( "Processing an action event." );
9.
super.processActionEvent( ae );
10.
}
11. }
On line 4, the constructor calls enableEvents(), passing in a constant that
enables processing of action events. The AWTEvent class defines 11
constants that can be used to enable processing of events; these constants
are listed in Table 10.2. (Event processing is automatically enabled when
event listeners are added, so if you restrict yourself to the listener model,
you never have to call enableEvents()).
Line 7 is the beginning of the subclass' version of the processActionEvent()
method. Notice the call on line 9 to the superclass' version. This call is
necessary because the superclass' version is responsible for calling
actionPerformed() on the button's action listeners; without line 9, action
listeners would be ignored.
Of course, you can always make a component subclass handle its own events
by making the subclass an event listener of itself, as shown in the listing
below:
1. class MyBtn extends Button implements ActionListener {
2.
public MyBtn( String label ) {
3.
super( label );
4.
addActionListener( this );
5.
}
6.
7.
public void actionPerformed( ActionEvent ae ) {
8.
// handle the event here
9.
}
10. }
The only difference between this strategy and the enableEvents() strategy is
the order in which event handlers are invoked. When you explicitly call
enableEvents(), the component's processActionEvent() method will be called
before any action listeners are notified. When the component subclass is its
own event listener, there is no guarantee as to order of notification.
Each of the 11 listener types has a corresponding XXX_EVENT_MASK constant defined in the AWTEvent class, and corresponding processXXXEvent()
methods. Table 10.2 lists the mask constants and the processing methods.
TABLE 10.2
Event masks
Mask
Method
AWTEvent.ACTION EVENT MASK
processActionEvent()
AWTEvent.ADJUSTMENT EVENT MASK processAdjustmentEvent()
AWTEvent.COMPONENT EVENT MASK processComponentEvent()
AWTEvent.CONTAINER EVENT MASK AprocessContainerEvent()
AWTEvent.FOCUS EVENT MASK
process FocusEvent()
AWTEvent.ITEM EVENT MASK
processItemEvent()
AWTEvent.KEY_EVENT_MASK
processKeyEvent()
AWTEvent.MOUSE_EVENT_MASK
processMouseEvent()
AWTEvent.MOUSE_MOTION_EVENT_MASK processMouseMotionEvent()
AWTEvent.TEXT_EVENT_MASK AWT processTextEvent()
Event.WINDOW EVENT MASK
processWindowEvent()
The strategy of explicitly enabling events for a component can be
summarized as follows:
1. Create a subclass of the component.
2. In the subclass constructor, call enableEvents(
AWTEvent.XXXEVENT_MASK ).
3. Provide the subclass with a processXXXEvent() method; this method
should call the superclass' version before returning.
Adapters
If you look at Table 1O.1, which lists the methods of the 11 event listener
interfaces, you will see that several of the interfaces have only a single
method, while others have several methods. The largest interface,
WindowListener, has seven methods.
Suppose you want to catch iconified events on a frame. You might try to
create the following class:
1. class MyIkeListener implements WindowListener {
2.
public void windowIconified( WindowEvent we ) {
3.
// process the event
4.
}
5. }
Unfortunately, this class will not compile. The WindowListener interface
defines seven methods, and class MylkeListener needs to implement the
other six before the compiler will be satisfied.
Typing in the remaining methods and giving them empty bodies is tedious.
The java.awt.event package provides seven adapter classes, one for each
listener interface that defines more than just a single method. An adapter is
simply a class that implements an interface by providing do-nothing
methods. For example, the WindowAdapter class implements the
WindowListener interface with seven do-nothing methods. Our example can
be modified to take advantage of this adapter:
1. class MylkeListener extends WindowAdapter {
2.
public void windowIconified( WindowEvent we ) {
3.
// process the event
4.
}
5. }
Table 10.3 lists all the adapter classes, along with the event-listener
interfaces that they implement.
TABLE 10.3
Adapters
Adapter Class
Listener Interface
ComponentAdapter
ContainerAdapter
FocusAdapter
KeyAdapter
MouseAdapter
MouseMotionAdapter
ComponentListener
ContainerListener
FocusListener
KeyListener
MouseListener
MouseMotionListener
WindowAdapter
Windowlistener
Chapter Summary
The event delegation model allows you to designate any object as a listener
for a component's events. A component may have multiple listeners for any
event type. All listeners must implement the appropriate interface. If the
interface defines more than one method, the listener may extend the
appropriate adapter class.
A component subclass may handle its own events by calling enableEvents(),
passing in an event mask. With this strategy, a processXXXEvent() method is
called before any listeners are notified.
Download