I l@ve RuBoard |
![]() ![]() |
27.5 Event UtilitiesIf you extend one of the Swing components to add functionality, or indeed, build your own component from scratch, you need to handle event listeners for any events you might generate. The EventListenerList class (from the javax.swing.event package) is designed to aid in that task. This class is similar in many ways to the AWTEventMulticaster; however, it supports any type of listener and assumes you'll use only the appropriate listeners for a given event type. The KeyStroke class can also help handle keyboard events. Rather than listening to every key that gets pressed and throwing out the things you don't care about, you can use the KeyStroke class to register specific actions with specific keys. The MouseInputAdapter can help deal with the other common low-level event generator: the mouse. And last but not least, this section also covers the SwingPropertyChangeSupport class to show you a fast way of generating property change events. 27.5.1 The EventListenerList ClassIf your component generates events, it must contain methods to add and remove interested listeners. Following the JavaBeans design patterns, these are the addTypeListener( ) and removeTypeListener( ) methods. Typically you store the listeners in a collection, and then use the vector as a rollcall for who to send events to when the time comes. This is a very common task for components that generate events, and the EventListenerList can help lift some (but certainly not all) of the burden of coding the event firing. The EventListenerList stores listeners as pairs of objects: one object to hold the listener's type and one to hold the listener itself. At any time, you can retrieve all of the current listeners as an array of Objects and use that array to fire off any events you need. Here is a SecretLabel class that extends JLabel and fires ActionEvent messages when clicked. The label does not give any indication it has been clicked; that's why it's called secret. The code for this label demonstrates how an EventListenerList is typically used. Figure 27-3 shows the SecretLabel up and running. Figure 27-3. A JLabel that uses an EventListenerList to facilitate dispatching events![]() We set up the standard addActionListener( ) and removeActionListener( ) methods, which delegate to the listener list, and pass in the type of listener we're attaching. (Recall that EventListenerList can store any type of listener.) When we actually fire an event, we search the listener list array, checking the even-numbered indices for a particular type of listener. If we find the right type (ActionListener, in this case) we use the next entry in the list as an event recipient. You can find other such examples throughout the Swing package in such models as DefaultTreeModel, DefaultTableModel, and DefaultButtonModel. The EventListenerList provides a generic dispatcher that works in just about every situation. However, it is not the only way to dispatch events. For a particular application you may find a more efficient means. // SecretLabel.java // An extension of the JLabel class that listens to mouse clicks and converts // them to ActionEvents, which in turn are reported via an EventListenersList object // import java.awt.*; import java.awt.event.*; import javax.swing.*; public class SecretLabel extends JLabel { public SecretLabel(String msg) { super(msg); addMouseListener(new MouseAdapter( ) { public void mouseClicked(MouseEvent me) { fireActionPerformed(new ActionEvent(SecretLabel.this, ActionEvent.ACTION_PERFORMED, "SecretMessage")); } }); } public void addActionListener(ActionListener l) { // We'll just use the listenerList we inherit from JComponent. listenerList.add(ActionListener.class, l); } public void removeActionListener(ActionListener l) { listenerList.remove(ActionListener.class, l); } protected void fireActionPerformed(ActionEvent ae) { Object[] listeners = listenerList.getListeners(ActionListener.class); for (int i = 0; i < listeners.length; i++) { ((ActionListener)listeners[i]).actionPerformed(ae); } } } Our addActionListener( ) and removeActionListener( ) methods just defer to a listener list to register and unregister listeners. We don't have to do anything special to get an EventListenerList; we're extending JLabel and therefore inherit a listenerList field from JComponent. fireActionPerformed( ) does the actual work; it calls the actionPerformed( ) method of every action listener stored in the listener list. Note that we walk through the array of listeners two at a time; as we'll see, the elements in this array alternate between Class objects that tell us what kind of listener we have, and the actual listener objects themselves. Figure 27-4 shows how the array is set up. Here's the application that creates the SecretLabel and hooks it up to the reporting label. We use the same addActionListener( ) that we would for things like buttons or lists: // SecretTest.java // A demonstration framework for the EventListenerList-enabled SecretLabel class // import javax.swing.*; import java.awt.event.*; import java.awt.*; public class SecretTest extends JFrame { public SecretTest( ) { super("EventListenerList Demo"); setSize(200, 100); setDefaultCloseOperation(EXIT_ON_CLOSE); SecretLabel secret = new SecretLabel("Try Clicking Me"); final JLabel reporter = new JLabel("Event reports will show here..."); secret.addActionListener(new ActionListener( ) { public void actionPerformed(ActionEvent ae) { reporter.setText("Got it: " + ae.getActionCommand( )); } } ); getContentPane( ).add(secret, BorderLayout.NORTH); getContentPane( ).add(reporter, BorderLayout.SOUTH); } public static void main(String args[]) { SecretTest st = new SecretTest( ); st.setVisible(true); } } If you have set up your own event source components before, the EventListenerList class may not seem to provide much improvement. But, as the documentation points out, it provides a single access point for serializing your list of listeners. 27.5.1.1 Constructor
27.5.1.2 Listener methods
Figure 27-4. The EventListenerList object array structure![]()
27.5.2 The KeyStroke ClassAnother convenient class for dealing with events is the KeyStroke class. This class allows you to associate actions with particular keys through the InputMap class. While not technically part of Swing, it plays an integral role in setting up the maps. 27.5.2.1 PropertiesThe KeyStroke class contains the properties shown in Table 27-5. The keyChar property is the character this keystroke represents, such as A or $. The keyCode property is the int value associated with a particular key on your keyboard. This might be the ASCII value of a letter, or some other value associated with a function key. The modifiers property contains information on whether or not any of the modifier keys (Control, Alt, Meta, Shift) are attached to this keystroke. The acceptable key codes come from the java.awt.event.KeyEvent class and are shown in Table 27-6. The onKeyRelease property determines when events associated with this keystroke should be triggered. A true value treats the keystroke as a keyTyped( ) event, while a false value behaves like a keyPressed( ) event.
27.5.2.2 Key codesJust for your reference, Table 27-6 lists the key codes defined by the java.awt.event.KeyEvent class. You'll notice that many of the key code values correspond to the ASCII value of the character associated with the key. This facilitates coding for common keys. Of course, as a good programmer, you always use the constant, right? In fact, even though you can use, for example, 'R' rather than VK_R, if you try to use 'r', it won't work. This is a good argument for using the constant; if you make a capitalization error the compiler will tell you right away, and you won't have to wait for bug reports from your users. Note that in the table we left out character equivalents that were not conceptually related to the virtual keycode constant. 27.5.2.3 Factory methodsThe KeyStroke class does not have a public (or even protected) constructor. All keystrokes are cached for you. You can use any of the static methods to retrieve the instance you're looking for.
27.5.3 The MouseInputAdapter ClassThis simple implementation of the MouseInputListener interface (which is itself just a conglomeration of the MouseListener and MouseMotionListener interfaces) provides empty methods for each of the mouse event handlers. You can use this abstract convenience class like any other adapter, extending it and overriding only the methods that interest you. This class simply has the benefit of handling both mouse and mouse motion events. 27.5.3.1 Methods
27.5.4 The SwingPropertyChangeSupport ClassMany Swing components support bound properties as defined by the JavaBeans specification. In the java.beans package, a utility class called PropertyChangeSupport is defined to help you register property change listeners and fire property change events. The PropertyChangeSupport class does this work in a thread-safe manner that consumes a good bit of memory. The SwingPropertyChangeSupport class provides exactly the same set of features but does so without thread-safety to reduce memory usage and increase performance. If you're building your own components, you can use this class instead of PropertyChangeSupport. 27.5.4.1 Constructor
27.5.4.2 Methods
![]() |
I l@ve RuBoard |
![]() ![]() |