|
Event and listener types
All Swing components include addXXXListener( ) and removeXXXListener( ) methods so that the appropriate types of listeners can be added and removed from each component. You’ll notice that the “XXX” in each case also represents the argument for the method, for example, addMyListener(MyListener m). The following table includes the basic associated events, listeners, and methods, along with the basic components that support those particular events by providing the addXXXListener( ) and removeXXXListener( ) methods. You should keep in mind that the event model is designed to be extensible, so you may encounter other events and listener types that are not covered in this table.
Event, listener interface and add- and remove-methods
|
Components supporting this event
|
ActionEvent ActionListener addActionListener( ) removeActionListener( )
|
JButton, JList, JTextField, JMenuItem and its derivatives including JCheckBoxMenuItem, JMenu, and JpopupMenu
|
AdjustmentEvent AdjustmentListener addAdjustmentListener( ) removeAdjustmentListener( )
|
JScrollbar and anything you create that implements the Adjustable interface
|
ComponentEvent ComponentListener addComponentListener( ) removeComponentListener( )
|
*Component and its derivatives, including JButton, JCheckBox, JComboBox, Container, JPanel, JApplet, JScrollPane, Window, JDialog, JFileDialog, JFrame, JLabel, JList, JScrollbar, JTextArea, and JTextField
|
ContainerEvent ContainerListener addContainerListener( ) removeContainerListener( )
|
Container and its derivatives, including JPanel, JApplet, JScrollPane, Window, JDialog, JFileDialog, and JFrame
|
FocusEvent FocusListener addFocusListener( ) removeFocusListener( )
|
Component and derivatives*
|
KeyEvent KeyListener addKeyListener( ) removeKeyListener( )
|
Component and derivatives*
|
MouseEvent (for both clicks and motion) MouseListener addMouseListener( ) removeMouseListener( )
|
Component and derivatives*
|
MouseEvent[81] (for both clicks and motion) MouseMotionListener addMouseMotionListener( ) removeMouseMotionListener( )
|
Component and derivatives*
|
WindowEvent WindowListener addWindowListener( ) removeWindowListener( )
|
Window and its derivatives, including JDialog, JFileDialog, and JFrame
|
ItemEvent ItemListener addItemListener( ) removeItemListener( )
|
JCheckBox, JCheckBoxMenuItem, JComboBox, JList, and anything that implements the ItemSelectable interface
|
TextEvent TextListener addTextListener( ) removeTextListener( )
|
Anything derived from JTextComponent, including JTextArea and JTextField
|
You can see that each type of component supports only certain types of events. It turns out to be rather difficult to look up all the events supported by each component. A simpler approach is to modify the ShowMethods.java program from Chapter 10 so that it displays all the event listeners supported by any Swing component that you enter.
Chapter 10 introduced reflection and used that feature to look up methods for a particular class—either the entire list of methods or a subset of those whose names match a keyword that you provide. The magic of reflection is that it can automatically show you all the methods for a class without forcing you to walk up the inheritance hierarchy, examining the base classes at each level. Thus, it provides a valuable timesaving tool for programming; because the names of most Java methods are made nicely verbose and descriptive, you can search for the method names that contain a particular word of interest. When you find what you think you’re looking for, check the JDK documentation.
However, by Chapter 10 you hadn’t seen Swing, so the tool in that chapter was developed as a command-line application. Here is the more useful GUI version, specialized to look for the “addListener” methods in Swing components:
//: c14:ShowAddListeners.java
// Display the "addXXXListener" methods of any Swing class.
// <applet code=ShowAddListeners
// width=500 height=400></applet>
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import java.lang.reflect.*;
import java.util.regex.*;
import com.bruceeckel.swing.*;
public class ShowAddListeners extends JApplet {
private JTextField name = new JTextField(25);
private JTextArea results = new JTextArea(40, 65);
private static Pattern addListener =
Pattern.compile("(add\\w+?Listener\\(.*?\\))");
private static Pattern qualifier =
Pattern.compile("\\w+\\.");
class NameL implements ActionListener {
public void actionPerformed(ActionEvent e) {
String nm = name.getText().trim();
if(nm.length() == 0) {
results.setText("No match");
return;
}
Class klass;
try {
klass = Class.forName("javax.swing." + nm);
} catch(ClassNotFoundException ex) {
results.setText("No match");
return;
}
Method[] methods = klass.getMethods();
results.setText("");
for(int i = 0; i < methods.length; i++) {
Matcher matcher =
addListener.matcher(methods[i].toString());
if(matcher.find())
results.append(qualifier.matcher(
matcher.group(1)).replaceAll("") + "\n");
}
}
}
public void init() {
NameL nameListener = new NameL();
name.addActionListener(nameListener);
JPanel top = new JPanel();
top.add(new JLabel("Swing class name (press ENTER):"));
top.add(name);
Container cp = getContentPane();
cp.add(BorderLayout.NORTH, top);
cp.add(new JScrollPane(results));
// Initial data and test:
name.setText("JTextArea");
nameListener.actionPerformed(
new ActionEvent("", 0 ,""));
}
public static void main(String[] args) {
Console.run(new ShowAddListeners(), 500,400);
}
} ///:~
You enter the Swing class name that you want to look up in the name JTextField. The results are extracted using regular expressions, and displayed in a JTextArea.
You’ll notice that there are no buttons or other components to indicate that you want the search to begin. That’s because the JTextField is monitored by an ActionListener. Whenever you make a change and press ENTER, the list is immediately updated. If the text field isn’t empty, it is used inside Class.forName( ) to try to look up the class. If the name is incorrect, Class.forName( ) will fail, which means that it throws an exception. This is trapped, and the JTextArea is set to “No match.” But if you type in a correct name (capitalization counts), Class.forName( ) is successful, and getMethods( ) will return an array of Method objects.
Two regular expressions are used here. The first, addListener, looks for “add” followed by any word characters, followed by “Listener” and the argument list in parentheses. Notice that this whole regular expression is surrounded by non-escaped parentheses, which means it will be accessible as a regular expression “group” when it matches. Inside NameL.ActionPerformed( ), a Matcher is created by passing each Method object to the Pattern.matcher( ) method. When find( ) is called for this Matcher object, it returns true only if a match occurs, and in that case you can select the first matching parenthesized group by calling group(1). This string still contains qualifiers, so to strip them off the qualifier Pattern object is used just as it was in c09:ShowMethods.java.
At the end of init( ), an initial value is placed in name and the action event is run to provide a test with initial data.
This program is a convenient way to investigate the capabilities of a Swing component. Once you know which events a particular component supports, you don’t need to look anything up to react to that event. You simply:
- Take the name of the event class and remove the word
“Event.” Add the word “Listener” to what
remains. This is the listener interface you must implement in your inner class.
- Implement the interface above and write out the methods for the events you
want to capture. For example, you might be looking for mouse movements, so you
write code for the mouseMoved( ) method of the
MouseMotionListener interface. (You must implement the other methods, of
course, but there’s often a shortcut for this, which you’ll see
soon.)
- Create an object of the listener class in Step 2. Register it with your
component with the method produced by prefixing “add” to your
listener name. For example, addMouseMotionListener( ).
Listener interface w/ adapter
|
Methods in interface
|
ActionListener
|
actionPerformed(ActionEvent)
|
AdjustmentListener
|
adjustmentValueChanged( AdjustmentEvent)
|
ComponentListener ComponentAdapter
|
componentHidden(ComponentEvent) componentShown(ComponentEvent) componentMoved(ComponentEvent) componentResized(ComponentEvent)
|
ContainerListener ContainerAdapter
|
componentAdded(ContainerEvent) componentRemoved(ContainerEvent)
|
FocusListener FocusAdapter
|
focusGained(FocusEvent) focusLost(FocusEvent)
|
KeyListener KeyAdapter
|
keyPressed(KeyEvent) keyReleased(KeyEvent) keyTyped(KeyEvent)
|
MouseListener MouseAdapter
|
mouseClicked(MouseEvent) mouseEntered(MouseEvent) mouseExited(MouseEvent) mousePressed(MouseEvent) mouseReleased(MouseEvent)
|
MouseMotionListener MouseMotionAdapter
|
mouseDragged(MouseEvent) mouseMoved(MouseEvent)
|
WindowListener WindowAdapter
|
windowOpened(WindowEvent) windowClosing(WindowEvent) windowClosed(WindowEvent) windowActivated(WindowEvent) windowDeactivated(WindowEvent) windowIconified(WindowEvent) windowDeiconified(WindowEvent)
|
ItemListener
|
itemStateChanged(ItemEvent)
|
This is not an exhaustive listing, partly because the event model allows you to create your own event types and associated listeners. Thus, you’ll regularly come across libraries that have invented their own events, and the knowledge gained in this chapter will allow you to figure out how to use these events.
Using listener adapters for simplicity
In the table above, you can see that some listener interfaces have only one method. These are trivial to implement, because you’ll implement them only when you want to write that particular method. However, the listener interfaces that have multiple methods can be less pleasant to use. For example, if you want to capture a mouse click (that isn’t already captured for you, for example, by a button), then you need to write a method for mouseClicked( ). But since MouseListener is an interface, you must implement all of the other methods even if they don’t do anything. This can be annoying.
To solve the problem, some (but not all) of the listener interfaces that have more than one method are provided with adapters, the names of which you can see in the table above. Each adapter provides default empty methods for each of the interface methods. Then all you need to do is inherit from the adapter and override only the methods you need to change. For example, the typical MouseListener you’ll use looks like this:
class MyMouseListener extends MouseAdapter {
public void mouseClicked(MouseEvent e) {
// Respond to mouse click...
}
}
The whole point of the adapters is to make the creation of listener classes easy.
There is a downside to adapters, however, in the form of a pitfall. Suppose you write a MouseAdapter like the previous one:
class MyMouseListener extends MouseAdapter {
public void MouseClicked(MouseEvent e) {
// Respond to mouse click...
}
}
This doesn’t work, but it will drive you crazy trying to figure out why, since everything will compile and run fine—except that your method won’t be called for a mouse click. Can you see the problem? It’s in the name of the method: MouseClicked( ) instead of mouseClicked ( ). A simple slip in capitalization results in the addition of a completely new method. However, this is not the method that’s called when the window is closing, so you don’t get the desired results. Despite the inconvenience, an interface will guarantee that the methods are properly implemented.
|
|