Writing Event Listeners |
[PENDING: update for Swing]When the AWT calls an event-listener method, that method executes in the AWT event thread. Because all other event-handling and drawing methods are executed in that same thread, a slow event-listener method can make the program seem unresponsive and slow to repaint itself.
If you need to perform some lengthy operation as the result of an event, do it by starting up another thread (or sending a request to another thread) to perform the operation. For help on using threads, see the lesson Doing Two or More Tasks at Once: Threads (page 327). [PENDING: link to threads and swing information instead]
Important: Make sure your event-listener methods execute quickly!
The next subsection introduces you to the ancestor of all AWT event classes, the AWTEvent class. After that, Using Adapters and Inner Classes to Handle AWT Events gives you hints for avoiding clutter in your code.
The AWTEvent Class
Each method in each AWT event listener interface has a single argument: an instance of a class that descends from the java.awt.AWTEvent class. The AWTEvent class doesn't define any methods or API that you ordinarily need to use. However, it does inherit a useful method from the java.util.EventObject class:Note that the getSource method returns an Object. Whenever possible, AWTEvent subclasses define similar methods with more restricted return types. For example, the ComponentEvent class defines a getComponent method that returns the Component that generated the event.
- Object getSource()
- Returns the object that generated the event.
Figure 68 shows the class hierarchy for the AWT event classes. As it shows, many but not all of the AWT event classes inherit from the ComponentEvent class.
The class hierarchy of the AWT event classes.
Standard AWT Events
The AWT defines nearly a dozen kinds of event listeners. You can tell what kinds of events a component can generate by looking at the kinds of event listeners you can register on it. For example, the Component class defines these listener registration methods:Thus, every class that inherits from Component supports component, focus, key, mouse, and mouse-motion listeners. However, most Component instances don't generate these events; a component generates only those events for which listeners have registered on it. For example, if a mouse listener is registered on a particular component, but the component has no other listeners, then the component will generate only mouse events--no component, focus, key, or mouse-motion events.
- addComponentListener
- addFocusListener
- addKeyListener
- addMouseListener
- addMouseMotionListener
Using Adapters and Inner Classes to Handle Events
This section tells you how to use adapters and inner classes to reduce clutter in your code. If you don't care about this subject, feel free to skip to the next section.Most listener interfaces, unlike
ActionListener
, contain more than one method. For example, theMouseListener
interface contains five methods:mousePressed
,mouseReleased
,mouseEntered
,mouseExited
, andmouseClicked
. Even if you care only about mouse clicks, if your class directly implementsMouseListener
, then you must implement all fiveMouseListener
methods. Methods for those events you don't care about can have empty bodies. Here's an example:Unfortunately, the resulting collection of empty method bodies can make code harder to read and maintain. To help you avoid cluttering your code with empty method bodies, the AWT and Swing provide an adapter class for each listener interface with more than one method. [PENDING: this is not entirely true for Swing.] (Handling Common Events lists all the listeners and their adapters.) For example, the//An example with cluttered but valid code. public class MyClass implements MouseListener { ... someObject.addMouseListener(this); ... /* Empty method definition. */ public void mousePressed(MouseEvent e) { } /* Empty method definition. */ public void mouseReleased(MouseEvent e) { } /* Empty method definition. */ public void mouseEntered(MouseEvent e) { } /* Empty method definition. */ public void mouseExited(MouseEvent e) { } public void mouseClicked(MouseEvent e) { ...//Event handler implementation goes here... } }MouseAdapter
class implements theMouseListener
interface. An adapter class implements empty versions of all its interface's methods.To use an adapter, you create a subclass of it, instead of directly implementing a listener interface. For example, by extending
MouseAdapter
, your class inherits empty definitions of all five of the methods thatMouseListener
contains./* * An example of extending an adapter class instead of * directly implementing a listener interface. */ public class MyClass extends MouseAdapter { ... someObject.addMouseListener(this); ... public void mouseClicked(MouseEvent e) { ...//Event handler implementation goes here... } }What if you don't want your event-handling class to inherit from an adapter class? For example, suppose you write an applet, and you want your
Applet
subclass to contain some code to handle mouse events. Since the Java language doesn't permit multiple inheritance, your class can't extend both theApplet
andMouseAdapter
classes. The solution is to define an inner class -- a class inside of yourApplet
subclass -- that extends theMouseAdapter
class,Here's another example of using an inner class://An example of using an inner class. public class MyClass extends Applet { ... someObject.addMouseListener(new MyAdapter()); ... class MyAdapter extends MouseAdapter { public void mouseClicked(MouseEvent e) { ...//Event handler implementation goes here... } } }Inner classes work well even if your event handler needs access to private instance variables from the enclosing class. As long as you don't declare an inner class to be//An example of using an anonymous inner class. public class MyClass extends Applet { ... someObject.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { ...//Event handler implementation goes here... } }); ... } }static
, an inner class can refer to instance variables and methods just as if its code is in the containing class. To make a local variable available to an inner class, just save a copy of the variable as afinal
local variable.
Note: Some 1.1 compilers don't let an inner class use private instance variables of the enclosing class. A workaround is to remove theprivate
specifier from the instance variable's declaration.
For more information about inner classes, see Implementing Nested Classes.
Writing Event Listeners |