Event Summary

Tables 16-1 and 16-2 summarize commonly used Swing events, which Swing components fire them, and the methods of the listener interfaces that receive them. The events and listeners are divided between the packages java.awt.event and javax.swing.event.

Table 16-1. Swing component and container events

Event

Fired by

Listener interface

Handler methods

java.awt.event.ComponentEvent

All components

ComponentListener

componentResized()

componentMoved()

componentShown()

componentHidden()

java.awt.event.FocusEvent

All components

FocusListener

focusGained()

focusLost()

java.awt.event.KeyEvent

All components

KeyListener

keyTyped()

keyPressed()

keyReleased()

java.awt.event.MouseEvent

All components

MouseListener

mouseClicked()

mousePressed()

mouseReleased()

mouseEntered()

mouseExited()

  

MouseMotionListener

mouseDragged()

mouseMoved()

java.awt.event.ContainerEvent

All containers

ContainerListener

componentAdded()

componentRemoved()

Table 16-2. Component-specific swing events

Event

Fired by

Listener interface

Handler method

java.awt.event.ActionEvent

JButton

JCheckBoxMenuItem

JComboBox

JFileChooser

JList

JRadioButtonMenuItem

JTextField

JToggleButton

ActionListener

actionPerformed()

java.awt.event.AdjustmentEvent

JScrollBar

Adjustment-Listener

adjustmentValue-Changed()

javax.swing.event.CaretEvent

JTextComponent

CaretListener

caretUpdate()

javax.swing.event.HyperlinkEvent

JEditorPane

JTextPane

Hyperlink-Listener

hyperlinkUpdate()

java.awt.event.InternalFrameEvent

JInternalFrame

InternalFrame-Listener

internalFrame-Activated()

internalFrame-Closed()

internalFrame-Closing()

internalFrame-Deactivated()

internalFrame-Deiconified()

internalFrame-Iconified()

internalFrame-Opened()

java.awt.event.ItemEvent

JCheckBoxMenuItem

JComboBox

JRadioButtonMenuItem

JToggleButton

ItemListener

itemStateChanged()

javax.swing.event.ListDataEvent

ListModel

ListDataListener

contentsChanged()

intervalAdded()

intervalRemoved()

javax.swing.event.ListSelectionEvent

JList

ListSelectionModel

ListSelection-Listener

valueChanged()

javax.swing.event.MenuEvent

JMenu

MenuListener

menuCanceled()

menuDeselected()

menuSelected()

javax.swing.event.PopupMenuEvent

JPopupMenu

PopupMenu-Listener

popupMenuCanceled()

popupMenuWill-BecomeInvisible()

popupMenuWill-BecomeVisible()

javax.swing.event.MenuKeyEvent

JMenuItem

MenuKeyListener

menuKeyPressed()

menuKeyReleased()

menuKeyTyped()

javax.swing.event.MenuDragMouseEvent

JMenuItem

MenuDragMouse-Listener

menuDragMouse-Dragged()

menuDragMouse-Entered()

menuDragMouse-Exited()

menuDragMouse-Released()

javax.swing.event.TableColumnModelEvent

TableColumnModel [a]

TableColumn-ModelListener

columnAdded()

columnMargin-Changed()

columnMoved()

columnRemoved()

columnSelection-Changed()

javax.swing.event.TableModelEvent

TableModel

TableModel-Listener

tableChanged()

javax.swing.event.TreeExpansionEvent

Jtree

TreeExpansion-Listener

treeCollapsed()

treeExpanded()

javax.swing.event.TreeModelEvent

TreeModel

TreeModel-Listener

treeNodesChanged()

treeNodesInserted()

treeNodesRemoved()

treeStructure-Changed()

javax.swing.event.TreeSelectionEvent

JTree

TreeSelectionModel

TreeSelection-Listener

valueChanged()

javax.swing.event.UndoableEditEvent

javax.swing.text.Document

UndoableEdit-Listener

undoableEdit-Happened()

java.awt.event.WindowEvent

JDialog

JFrame

JWindow

WindowListener

windowOpened()

windowClosing()

windowClosed()

windowIconified()

windowDeiconified()

windowActivated()

windowDeactivated()

[a] The TableColumnModel class breaks with convention in the names of the methods that add listeners. They are addColumnModelListener() and removeColumnModelListener().

In Swing, a component’s model and view are distinct. Strictly speaking, components don’t fire events; models do. When you press a JButton, for example, it’s actually the button’s data model that fires an ActionEvent, not the button itself. But JButton has a convenience method for registering ActionListeners; this method passes its argument through to register the listener with the button model. In many cases (as with JButtons), you don’t have to deal with the data model separately from the view, so we can speak loosely of the component itself firing the events. InputEvents are, of course, generated by the native input system and fired for the appropriate component, although the listener responds as though they’re generated by the component.

Adapter Classes

It’s not ideal to have your application components implement a bunch of listener interfaces and receive events directly. Sometimes it’s not even possible. Being an event receiver forces you to modify or subclass your objects to implement the appropriate event listener interfaces and add the code necessary to handle the events. And because we are talking about Swing events here, a more subtle issue is that you would be, of necessity, building GUI logic into parts of your application that shouldn’t have to know anything about the GUI. Let’s look at an example.

In Figure 16-4, we drew the plans for our Vegomatic food processor. We made our Vegomatic object implement the ActionListener interface so that it can receive events directly from the three JButton components: Chop, Puree, and Frappe. The problem is that our Vegomatic object now has to know more than how to mangle food. It also has to be aware that it is driven by three controls—specifically, buttons that send action commands—and be aware of which methods it should invoke for those commands. Our boxes labeling the GUI and application code overlap in an unwholesome way. If the marketing people should later want to add or remove buttons or perhaps just change the names, we have to be careful. We may have to modify the logic in our Vegomatic object. All is not well.

An alternative is to place an adapter class between our event source and receiver. An adapter is a simple object whose sole purpose is to map an incoming event to an outgoing method.

Figure 16-5 shows a better design that uses three adapter classes, one for each button. The implementation of the first adapter might look like:

    class VegomaticAdapter1 implements ActionListener {
        Vegomatic vegomatic;
        VegomaticAdapter1 ( Vegomatic vegomatic ) {
            this.vegomatic = vegomatic;
        }
        public void actionPerformed( ActionEvent e ) {
            vegomatic.chopFood();
        }
    }
Implementing the ActionListener interface directly

Figure 16-4. Implementing the ActionListener interface directly

Implementing the ActionListener interface using adapter classes

Figure 16-5. Implementing the ActionListener interface using adapter classes

So somewhere in the code where we build our GUI, we could register our listener like this:

    Vegomatic theVegomatic = ...;
    Button chopButton = ...;

    // make the hookup
    chopButton.addActionListener( new VegomaticAdapter1(theVegomatic) );

Instead of registering itself (this) as the Button’s listener, the adapter registers the Vegomatic object (theVegomatic). In this way, the adapter acts as an intermediary, hooking up an event source (the button) with an event receiver (the virtual chopper).

We have completely separated the messiness of our GUI from the application code. However, we have added three new classes to our application, none of which does very much. Is that good? It depends on your vantage point.

Under different circumstances, our buttons may have been able to share a common adapter class that was simply instantiated with different parameters. Various tradeoffs can be made between size, efficiency, and elegance of code. Adapter classes will often be generated automatically by development tools. The way we’ve named our adapter classes VegomaticAdapter1, VegomaticAdapter2, and VegomaticAdapter3 hints at this. More often, when handcoding, you’ll use an anonymous inner class, as we’ll see in the next section. At the other extreme, we can forsake Java’s strong typing and use the Reflection API to create a completely dynamic hookup between an event source and its listener.

Dummy Adapters

Many listener interfaces contain more than one event handler method. Unfortunately, this means that to register yourself as interested in any one of those events, you must implement the whole listener interface. To accomplish this, you might find yourself typing dummy “stubbed-out” methods to complete the interface. There is nothing wrong with this, but it is a bit tedious. To save you some trouble, AWT and Swing provide some helper classes that implement these dummy methods for you. For each of the most common listener interfaces containing more than one method, there is an adapter class containing the stubbed methods. You can use the adapter class as a base class for your own adapters. When you need a class to patch together your event source and listener, you can subclass the adapter and override only the methods you want.

For example, the MouseAdapter class implements the MouseListener interface and provides the following minimalist implementation:

    public void mouseClicked(MouseEvent e) {};
    public void mousePressed(MouseEvent e) {};
    public void mouseReleased(MouseEvent e) {};
    public void mouseEntered(MouseEvent e) {};
    public void mouseExited(MouseEvent e) {};

This isn’t a tremendous time saver; it’s simply a bit of sugar. The primary advantage comes into play when we use the MouseAdapter as the base for our own adapter in an anonymous inner class. For example, suppose we want to catch a mousePressed() event in some component and blow up a building. We can use the following to make the hookup:

    someComponent.addMouseListener( new MouseAdapter() {
        public void MousePressed(MouseEvent e) {
            building.blowUp();
        }
    } );

We’ve taken artistic liberties with the formatting, but it’s pretty readable. Moreover, we’ve avoided creating stub methods for the four unused event handler methods. Writing adapters is common enough that it’s nice to avoid typing those extra few lines and perhaps stave off the onset of carpal tunnel syndrome for a few more hours. Remember that any time you use an inner class, the compiler is generating a class for you, so the messiness you’ve saved in your source still exists in the output classes.

Get Learning Java, 4th Edition now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.