The JavaTM Tutorial

| Start of Tutorial > Start of Trail > Start of Lesson | Search

Trail: Creating a GUI with JFC/Swing
Lesson: Writing Event Listeners

## General Information about Writing Event Listeners

> From Event Handling, you should already know the basics of event listeners. For example, you can attach multiple listeners to a single event source. Most importantly, event-listener methods should execute quickly. Because all event-handling and drawing methods are executed in the same thread, a slow event-listener method can make the program seem unresponsive and slow to repaint itself.

> First, this section introduces you to event objects -- small objects that describe each event. In particular, we talk about `EventObject`, the superclass for all AWT and Swing events. After that this section describes two major categories of events, then gives you hints for avoiding clutter in your code.

> - Getting Event Information: Event Objects
> - Low-level Events and Semantic Events
> - Using Adapters and Inner Classes to Handle AWT Events

### Getting Event Information: Event Objects

> Every event-listener method has a single argument -- an object that inherits from the `EventObject` class. Although the argument always descends from `EventObject`, its type is generally specified more precisely. For example, the argument for methods that handle mouse events is an instance of `MouseEvent`, where `MouseEvent` is an indirect subclass of `EventObject`.

> The `EventObject` class defines one very useful method:

> `Object getSource()`
>   Returns the object that fired the event.

> Note that the `getSource` method returns an `Object`. Event classes sometimes define methods similar to `getSource`, but that have more restricted return types. For example, the `ComponentEvent` class defines a `getComponent` method that -- just like `getSource` -- returns the object that fired the event. The difference is that `getComponent` always returns a `Component`. Each how-to page in this lesson describes whether you should use `getSource` or another method to get the event source.

> Often, an event class defines methods that return information about the event. For example, you can query a `MouseEvent` object for information about where the event occurred, how many clicks the user made, which modifier keys were pressed, and so on.

### Concepts: Low-Level Events and Semantic Events

> Events can be divided into two groups: low-level events and semantic events. Low-level events represent window-system occurrences or low-level input. Everything else is a semantic event.

> Mouse and key events -- both of which result directly from user input -- are low-level events. Other low-level events include component, container, focus, and window events. Component events let you track changes to a component's position, size, and visibility. Container events let you know when any component is added to or removed from a particular container. Focus events tell you when a component gains or loses the keyboard focus -- the ability to receive characters typed at the keyboard. Window events keep you informed of the basic status of any kind of `Window`, such as a `Dialog` or a `Frame`.

> Examples of semantic events include action events, item events, and list selection events. The trigger for a semantic event can differ by component. For example, a button customarily fires an action event when the user clicks it, but a text field fires an action event when the user presses Return. The trigger can also vary by look and feel. For example, an audio look and feel might implement a button that fires an action event when the user says a certain phrase. Some semantic events aren't triggered by low-level events, at all. For example, a table-model event might be fired when a table model receives new data from a database.

> Whenever possible, you should listen for semantic events rather than low-level events. That way, you can make your code as robust and portable as possible. For example, listening for action events on buttons, rather than mouse events, means that the button will react appropriately when the user tries to activate the button using a keyboard alternative or a look-and-feel-specific gesture. When dealing with a compound component such as a combo box, it's imperative that you stick to semantic events, since you have no reliable way of registering listeners on all the look-and-feel-specific components that might be used to form the compound component.

### Using Adapters and Inner Classes to Handle Events

> This subsection 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 contain more than one method. For example, the `MouseListener` interface contains five methods: `mousePressed`, `mouseReleased`, `mouseEntered`, `mouseExited`, and `mouseClicked`. Even if you care only about mouse clicks, if your class directly implements `MouseListener`, then you must implement all five `MouseListener` methods. Methods for those events you don't care about can have empty bodies. Here's an example:

> >     //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...
> >         }
> >     }

> 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 API generally includes an adapter class for each listener interface with more than one method. (Handling Common Events lists all the listeners and their adapters.) For example, the `MouseAdapter` class implements the `MouseListener` 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 that `MouseListener` 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 the `Applet` and `MouseAdapter` classes. The solution is to define an inner class -- a class inside of your `Applet` subclass -- that extends the `MouseAdapter` 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...
> >             }
> >         }
> >     }

> Here's an example of using an anonymous inner class:

> >     //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...
> >                 }
> >     	});
> >         ...
> >         }
> >     }

> 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 `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 a `final` 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 the `private` specifier from the instance variable's declaration.

> To refer to the enclosing instance, you can use `EnclosingClass.this`. For more information about inner classes, see Implementing Nested Classes.

| Start of Tutorial > Start of Trail > Start of Lesson | Search