Building a GUI: Events and Listeners

   

In the second phase of the GUI building process, the focus is on the feel of a GUI. To achieve this feel, you'll work with the windowing toolkit's events and listeners. After you've integrated this feel with a GUI's look, you're almost finished. (All that is left is to test your GUI.)

Exploring Events

An event is fired when a user presses a button, scrolls through a list of textual items, makes a selection from a menu, moves the mouse, presses a key, and so on. These events originate with the component's peer and are forwarded by the windowing toolkit to a corresponding object. This object is understood to be the source of the event.

The windowing toolkit associates events with objects that provide descriptive information about what happened , and are created from subclasses of the abstract AWTEvent class (located in the java.awt package). Getting to know AWTEvent and its subclasses is the fourth step in building a GUI.

The event class hierarchy is shown in Figure 14.21. ( AWTEvent and InputEvent appear in gray because they are abstract classes.)

Figure 14.21. The windowing toolkit organizes event classes into a hierarchy.

graphics/14fig21.gif

If you look carefully , you'll notice that AWTEvent inherits from the EventObject class (located in the java.util package). This class encapsulates the concept of being a source, and provides a getSource method that returns an event's source.

The HierarchyEvent class is new to the Java 2 Platform Standard Edition, Version 1.3. Objects created from this class represent events that are fired when a change is made to the component and container hierarchy. For example, a hierarchy event is fired when a panel is added to another container (such as a frame). These events are provided for notification purposes only, because the windowing toolkit automatically takes care of these changes.

AWTEvent provides several constants (such as ACTION_EVENT_MASK ) that are useful when processing events without using listeners. These constants are used in conjunction with Component 's enableEvents method. AWTEvent also provides methods for use with peers.

Event objects are typically created behind the scenes, by calling a constructor in the appropriate event class. Normally, you will not be creating these objects. For this reason, these constructors will not be discussed when some of the more common event classes are explored. (To explore all the event classes in detail, consult the SDK documentation.)

Action Events

Action events are generated by components when component-specific actions occur. For example, an action occurs when a user presses a button or selects a menu item. This results in an action event being generated. Objects representing action events are created from the ActionEvent class (located in the java.awt.event package).

When an action event occurs, it is possible that a user might be holding down the Alt, Ctrl, Meta, or Shift key. This key can be used to modify the purpose of the action event. For example, a simple button press might accomplish one thing, whereas pressing the Alt key in conjunction with a button press might accomplish something slightly different. For this reason, these four keys are known as modifiers .

ActionEvent provides the getModifiers method to return an integer value that identifies all pressed modifiers. To distinguish between multiple modifiers, you need to use one of the four constants provided by ActionEvent ALT_MASK, CTRL_MASK, META_MASK, and SHIFT_MASK ”in conjunction with the bitwise AND operator. A nonzero result means the modifier was pressed when the action event occurred. The following code fragment shows how to isolate a modifier by using a mask. This code fragment determines whether Alt was pressed. (An ActionEvent object referenced by e is assumed.)

 if (e.getModifiers () & ActionEvent.ALT_MASK) {  } 

If you are writing an internationalized program, you will want to identify the button that was pressed or the menu item that was selected. You can simplify this task by using nonlocalized identifiers. When a component object is created, you call its setActionCommand method to assign an identifier. When the action event occurs, call getActionCommand to retrieve this identifier.

Focus Events

Focus events occur when a component either gains or loses focus. For example, when a user is tabbing from one component to another in a dialog, one of these components gains focus, whereas the other loses focus. Objects representing focus events are created from the FocusEvent class (located in the java.awt.event package).

A focus change can be temporary or permanent. For example, when a window appears in front of another, this is a temporary change of focus. In contrast, a permanent change of focus occurs when the mouse is used to click in a text field or the Tab key is used to switch to another component. FocusEvent 's isTemporary method returns a Boolean true value if the focus change is temporary and a Boolean false value if this change is permanent.

Item Events

Item events occur when a user selects a check box, check box menu item, choice item, or list item (or items). Objects representing item events are created from the ItemEvent class (located in the java.awt.event package).

Whereas ItemEvent 's inherited getSource method returns the source of the event, this source can be narrowed down to the actual item (for choices and lists) or items (for lists), by calling the getItemSelectable method, which returns a reference to an object implementing the ItemSelectable interface (located in the java.awt package). Call ItemSelectable 's getSelectedItems method to fetch an array of all selected items. (Remember, lists can operate in multiple selection mode, allowing a user to select more than one item.)

Item events are fired when an item is selected or deselected. These two states are represented by the SELECTED and DESELECTED constants in the ItemEvent class. Furthermore, to discover whether an item was selected or deselected, call ItemEvent 's getStateChange method.

Key Events

Key events occur when a user presses or releases a key, and fall into three categories: key pressed, key released, and key typed. A key pressed event occurs when a user presses a key and a key released event occurs when a user releases the key. The key that was pressed/released is represented by a key code (a 32-bit int ) and each key on the keyboard is assigned its own unique key code. A key typed event occurs when one or more keys are pressed to generate a single Unicode character (a 16-bit char ). For example, pressing the A key results in a key typed event that represents a lowercase letter a, whereas simultaneously pressing both the A key and either Shift key results in a key typed event that represents an uppercase letter A. Keep in mind that the order of events is key pressed followed by key typed followed by key released.

For every key typed event, there is at least one key pressed event. For example, when you press the A key by itself, a single key pressed event is fired, which is followed by a single key typed event. Now, if you press either Shift key and then press the A key, a key pressed event is fired for the Shift key. This is followed by a key pressed event being fired for the A key. Finally, a key typed event is fired that represents an uppercase letter A. Some key pressed events do not result in any key typed events. For example, if you press a Shift key, a key pressed event is fired. However, a key typed event is not fired because a Shift key does not represent a character.

Objects representing key events are created from the KeyEvent class (located in the java.awt.event package).

KeyEvent provides a variety of constants (such as VK_ENTER, VK_A, and VK_ALT ) that identify key codes. These key codes are also known as virtual keys because they are independent of any windowing system. To retrieve a key code from a key event object, call KeyEvent 's getKeyCode method. This method returns the VK_UNDEFINED constant if called for a key typed event.

You can compare getKeyCode 's return value against one of the virtual key constants to determine which key was pressed. The following code fragment demonstrates this comparison. (A KeyEvent object referenced by e is assumed.)

 if (e.getKeyCode () == KeyEvent.VK_ENTER) {  } 

In the case of a key typed event, you are more interested in a character. You can obtain this character by calling getKeyChar. This method returns KeyEvent 's CHAR_UNDEFINED constant if there is no character associated with the key code.

You can compare getKeyChar 's return value against a character literal to determine which character is represented by the event. The following code fragment demonstrates this comparison. (A KeyEvent object referenced by e is assumed.)

 if (e.getKeyChar () == 'A') {  } 
Mouse Events

Mouse events occur when a user presses a mouse button, releases a mouse button, or moves the mouse pointer. Objects representing mouse events are created from the MouseEvent class (located in the java.awt.event package).

MouseEvent 's getX and getY methods return the coordinates of the mouse pointer. These coordinates are relative to the coordinates of the source. Instead of retrieving these coordinates separately, you can retrieve them together as one Point object by calling getPoint.

When working with pop-up menus , you will need to call MouseEvent 's isPopupTrigger method. This method retrieves the pop-up trigger setting (a Boolean value that is true when a user has chosen to activate a pop-up menu). This is demonstrated in the following code fragment. (A MouseEvent object referenced by e is assumed. Furthermore, a pop-up menu component identified by popup is assumed.)

 if (e.isPopupTrigger ())     popup.show (e.getComponent (), e.getX (), e.getY ()); 

The getComponent method (inherited from the ComponentEvent class) identifies the component to which a pop-up menu is attached. Its coordinate system is used in partnership with the returned values from getX and getY to identify the upper-left corner of the pop-up menu.

Text Events

Text events occur when the contents of a text area or a text field change, or a user presses Return when a text field has the focus. A change happens by pressing keys (when this component has the focus) or by calling the component's setText method. Objects representing text events are created from the TextEvent class (located in the java.awt.event package).

Window Events

Window events occur when a window is activated, deactivated, opened, closing, closed, iconified , or deiconified. Objects representing window events are created from the WindowEvent class (located in the java.awt.event package). To identify the container window ”dialog, file dialog, or frame ”that fired the event, call WindowEvent 's getWindow method.

Exploring Listeners

There is hardly any point in firing an event when there is no one around to listen for that event and take appropriate action. The ability to create and register listeners is the final step in the GUI building process.

A listener object registers itself with a source. The source will then call the listener when an event occurs. Figure 14.22 illustrates the process of sending an event from a component peer to its object (via the AWT), and then forwarding the event object from this source to a registered listener.

Figure 14.22. An event is fired from a component peer to a component object, and then forwarded to a listener.

graphics/14fig22.gif

To become a registered listener to a source's events, an object must be created from a class that implements a listener interface and must also call a source registration method.

The HierarchyListener interface is new to the Java 2 Platform Standard Edition, ersion 1.3. Objects created from classes that implement this interface can register themselves as listeners for hierarchy events.

Action Listeners

Action listeners listen for action events. They are represented by objects implementing the ActionListener interface (located in the java.awt.event package).

ActionListener specifies a single method that must be implemented by an action listener's class. This method has the following signature:

 public abstract void actionPerformed (ActionEvent e) 

The actionPerformed method is called when a button is pressed or a menu item is selected.

To register with an action source, an action listener must call the source's addActionListener method. (To de-register, an action listener would call the source's removeActionListener method.)

Listing 14.16 presents the source code to an ActionListenerDemo1 applet that demonstrates listening for action events.

Listing 14.16 The ActionListenerDemo1 Applet Source Code
 // ActionListenerDemo1.java import java.awt.*; import java.applet.*; import java.awt.event.*; public class ActionListenerDemo1 extends Applet                                  implements ActionListener {    public void init ()    {       String [] cursorNames =       {          "DEFAULT_CURSOR",          "CROSSHAIR_CURSOR",          "TEXT_CURSOR",          "WAIT_CURSOR",          "HAND_CURSOR",          "MOVE_CURSOR",          "N_RESIZE_CURSOR",          "S_RESIZE_CURSOR",          "E_RESIZE_CURSOR",          "W_RESIZE_CURSOR",          "NE_RESIZE_CURSOR",          "NW_RESIZE_CURSOR",          "SE_RESIZE_CURSOR",          "SW_RESIZE_CURSOR"       } ;       int [] cursorTypes =       {          Cursor.DEFAULT_CURSOR,          Cursor.CROSSHAIR_CURSOR,          Cursor.TEXT_CURSOR,          Cursor.WAIT_CURSOR,          Cursor.HAND_CURSOR,          Cursor.MOVE_CURSOR,          Cursor.N_RESIZE_CURSOR,          Cursor.S_RESIZE_CURSOR,          Cursor.E_RESIZE_CURSOR,          Cursor.W_RESIZE_CURSOR,          Cursor.NE_RESIZE_CURSOR,          Cursor.NW_RESIZE_CURSOR,          Cursor.SE_RESIZE_CURSOR,          Cursor.SW_RESIZE_CURSOR       } ;       for (int i = 0; i < cursorNames.length; i++)       {            Button b = new Button (cursorNames [i]);            b.setActionCommand ("" + i);            b.setCursor (Cursor.getPredefinedCursor (cursorTypes [i]));            b.addActionListener (this);            add (b);       } ;    }    public void actionPerformed (ActionEvent e)    {       String id = e.getActionCommand ();       AudioClip ac = getAudioClip (getDocumentBase (), id + ".au");       ac.play ();    } } 

ActionListenerDemo1 displays a GUI consisting of several buttons . Each button contains the name of a constant in the Cursor class. When you move the mouse pointer over a button, its icon changes to reflect the button's cursor. Figure 14.23 shows this GUI.

Figure 14.23. ActionListener Demo1 demonstrates action events ”and more.

graphics/14fig23.gif

ActionListenerDemo1 implements the ActionListener interface by providing an actionPerformed method. It establishes a GUI in its init method. As part of this process, buttons are created. For each button, the setActionCommand method is called to give this button a unique ID. Then, the setCursor method is called to establish the cursor that will appear when the mouse pointer is moved over this button. The button's addActionListener method is called to register the applet as a listener for action events that originate from this button. Finally, the button is added to the applet's panel container. When an action event occurs, actionPerformed is called. To handle this event, actionPerformed calls getActionCommand to retrieve the button's ID. It uses this ID to choose an appropriate sound file, which is subsequently played .

Applets and applications are capable of producing sounds by calling one of two overloaded getAudioClip methods (for applets) and the newAudioClip method (for applications). These methods are located in the Applet class and require a URL argument that identifies the location and name of a sound file. (The following sound file formats are supported: AIFF, AU, MIDI, RMF, and WAV.)

Each method returns an object that implements the AudioClip interface (located in the java.applet package). This object is known as an audio clip . AudioClip specifies three methods that the audio clip's class implements. These methods are presented in Table 14.9.

Table 14.9. AudioClip 's Methods
Method Description
loop Play an audio clip in a continuous loop.
play Play an audio clip once.
stop Stop an audio clip that is currently playing.

When you click one of ActionListenerDemo1 's buttons, you will hear a voice identifying the cursor. If you click another button before this sound finishes, a new sound will begin and can be simultaneously heard with the other sound.

ActionListenerDemo1 integrates GUI presentation and the handling of events. However, by separating these tasks , you can simplify your GUI and promote reusable code. Listing 14.17 presents the source code to an ActionListenerDemo2 application that demonstrates event handling/presentation separation, along with action events from an application perspective. (Press Ctrl+C, or the equivalent, to terminate this program.)

Listing 14.17 The ActionListenerDemo2 Application Source Code
 // ActionListenerDemo2.java import java.awt.*; import java.net.*; import java.applet.*; import java.awt.event.*; class MakeSomeNoise implements ActionListener {    public void actionPerformed (ActionEvent e)    {       try       {          String id = e.getActionCommand ();          URL url = new URL ("file:" + id + ".au");          AudioClip ac = Applet.newAudioClip (url);          ac.play ();       }       catch (MalformedURLException e2) { }    } } public class ActionListenerDemo2 extends Frame {    ActionListenerDemo2 (String title)    {       super (title);       String [] cursorNames =       {          "DEFAULT_CURSOR",          "CROSSHAIR_CURSOR",          "TEXT_CURSOR",          "WAIT_CURSOR",          "HAND_CURSOR",          "MOVE_CURSOR",          "N_RESIZE_CURSOR",          "S_RESIZE_CURSOR",          "E_RESIZE_CURSOR",          "W_RESIZE_CURSOR",          "NE_RESIZE_CURSOR",          "NW_RESIZE_CURSOR",          "SE_RESIZE_CURSOR",          "SW_RESIZE_CURSOR"       } ;       int [] cursorTypes =       {          Cursor.DEFAULT_CURSOR,          Cursor.CROSSHAIR_CURSOR,          Cursor.TEXT_CURSOR,          Cursor.WAIT_CURSOR,          Cursor.HAND_CURSOR,          Cursor.MOVE_CURSOR,          Cursor.N_RESIZE_CURSOR,          Cursor.S_RESIZE_CURSOR,          Cursor.E_RESIZE_CURSOR,          Cursor.W_RESIZE_CURSOR,          Cursor.NE_RESIZE_CURSOR,          Cursor.NW_RESIZE_CURSOR,          Cursor.SE_RESIZE_CURSOR,          Cursor.SW_RESIZE_CURSOR       } ;       Panel p = new Panel ();       for (int i = 0; i < cursorNames.length; i++)       {            Button b = new Button (cursorNames [i]);            b.setActionCommand ("" + i);            b.setCursor (Cursor.getPredefinedCursor (cursorTypes [i]));            b.addActionListener (new MakeSomeNoise ());            p.add (b);       } ;       add (p);       setSize (450, 200);       setVisible (true);    }    public static void main (String [] args)    {       new ActionListenerDemo2 ("Action Listener Demo2");    } } 
Focus Listeners

Focus listeners listen for focus events. They are represented by objects implementing the FocusListener interface (located in the java.awt.event package).

FocusListener specifies two methods that must be implemented by a focus listener's class. These methods have the following signatures:

 public abstract void focusGained (FocusEvent e) public abstract void focusLost (FocusEvent e) 

When the very first focus event occurs, focusGained is called for the component that receives focus. (This would be the very first component added to a container that is capable of receiving focus.) For each subsequent focus event, focusLost is called for the component losing focus and then focusGained is called for the component receiving focus.

To register with a focus source, a focus listener must call the source's addFocusListener method. (To de-register, a focus listener would call the source's removeFocusListener method.)

Listing 14.18 presents the source code to a FocusListenerDemo application that demonstrates listening for focus events. (Press Ctrl+C, or the equivalent, to terminate this program.)

Listing 14.18 The FocusListenerDemo Application Source Code
 // FocusListenerDemo.java import java.awt.*; import java.awt.event.*; class FocusListenerDemo extends Frame implements FocusListener {    TextField numField;    FocusListenerDemo (String title)    {       super (title);       Panel p = new Panel ();       p.add (new Label ("Please enter a number:"));       numField = new TextField (20);       numField.addFocusListener (this);       p.add (numField);       add (p, "North");       p = new Panel ();       p.add (new Label ("Please enter a name:"));       TextField nameField = new TextField (20);       nameField.addFocusListener (this);       p.add (nameField);       add (p, "South");       setSize (350, 100);       setVisible (true);    }    public void focusGained (FocusEvent e)    {       Component c = (Component) e.getSource ();       System.out.println ("GAIN: " + c.getName ());    }    public void focusLost (FocusEvent e)    {       Component c = (Component) e.getSource ();       System.out.println ("LOST: " + c.getName ());       if (e.getSource () == numField)           try           {              int i = Integer.parseInt (numField.getText ());           }           catch (NumberFormatException e2)           {              numField.requestFocus ();           }    }    public static void main (String [] args)    {       new FocusListenerDemo ("Focus Listener Demo");    } } 

FocusListenerDemo displays a GUI consisting of a pair of labels and two text fields. One of these text fields is used to input a number, whereas the other text field is used to input a name.

As you know, users don't necessarily do what a program asks. For example, a user might try to enter a name in the number field and then move to the name field. To prevent this from happening, you can force the user to remain in the number field until a valid number is entered. This is accomplished in part by listening for focus change events. When a focus event occurs, focusLost will be called when the number field loses focus. After displaying the name of the component losing focus, the code checks to see if this component is the number field. If it is, the code tries to convert the contents of that field to an integer, by calling Integer.parseInt. This method throws a NumberFormatException object if it cannot parse these contents into an integer. If this should happen, the requestFocus method for the number field object is called in the exception handler. This method call immediately transfers focus back to the number field. As a result, the user is not allowed to exit this field until a valid number has been entered. FocusListenerDemo 's GUI is shown in Figure 14.24.

Figure 14.24. FocusListener Demo demonstrates focus events.

graphics/14fig24.gif

Item Listeners

Item listeners listen for item events. They are represented by objects implementing the ItemListener interface (located in the java.awt.event package).

ItemListener specifies a single method that must be implemented by an item listener's class. This method has the following signature:

 public abstract void itemStateChanged (ItemEvent e) 

The itemStateChanged method is called when the state of a check box, check box menu item, choice, or list changes. For example, selecting an item from a list ”by clicking that item ”changes the state of that component.

To register with an item source, an item listener must call the source's addItemListener method. (To de-register, an item listener would call the source's removeItemListener method.)

For an example of an item listener, please review the source code to Chapter 12's PNViewer1 AWT application.

Note

Although PNViewer1 is mentioned in Chapter 12, its source code is not listed in the chapter. Instead, PNViewer1 's fully-commented source code is included with the rest of this book's source code. You will need to download PNViewer1 's source code (along with the rest of this book's source code) from MacMillan's Web site.


Key Listeners

Key listeners listen for key events. They are represented by objects implementing the KeyListener interface (located in the java.awt.event package).

KeyListener specifies three methods that must be implemented by a key listener's class. These methods have the following signatures:

 public abstract void keyPressed (KeyEvent e) public abstract void keyReleased (KeyEvent e) public abstract void keyTyped (KeyEvent e) 

The keyPressed method is called when a key pressed event occurs, the keyReleased method is called when a key released event occurs, and the keyTyped method is called when a key typed event occurs.

To register with a key source, a key listener must call the source's addKeyListener method. (To de-register, a key listener would call the source's removeKeyListener method.)

Listing 14.19 presents the source code to a KeyListenerDemo application that demonstrates listening for key events. (Press Ctrl+C, or the equivalent, to terminate this program.)

Listing 14.19 The KeyListenerDemo Application Source Code
 // KeyListenerDemo.java import java.awt.*; import java.awt.event.*; class KeyListenerDemo extends Frame implements KeyListener {    KeyListenerDemo (String title)    {       super (title);       addKeyListener (this);       setSize (100, 100);       setVisible (true);    }    public void keyPressed (KeyEvent e)    {       System.out.println ("Key pressed: virtual key code = "                           + e.getKeyCode ());    }    public void keyReleased (KeyEvent e)    {       System.out.println ("Key released: virtual key code = "                           + e.getKeyCode ());    }    public void keyTyped (KeyEvent e)    {       System.out.println ("Key typed: character = "                           + e.getKeyChar ());    }    public static void main (String [] args)    {       new KeyListenerDemo ("Key Listener Demo");    } } 

KeyListenerDemo sends messages to the standard output device when key events occur. For example, when Shift and then A is pressed, the following is output:

 Key pressed: virtual key code = 16 Key pressed: virtual key code = 65 Key typed: character = A Key released: virtual key code = 65 Key released: virtual key code = 16 

Caution

You might see multiple key pressed, key released, and key typed lines because of a keyboard's auto-repeat feature ”which is triggered when you keep pressing a key past a minimum amount of time.


Mouse Listeners

Mouse listeners listen for mouse events. Mouse button- related events are represented by objects implementing the MouseListener interface (located in the java.awt.event package). In contrast, mouse movement-related events are represented by objects implementing the MouseMotionListener interface (also located in the java.awt.event package). This separation makes it easy to ignore mouse motion events (which happen quite frequently and can slow down performance).

MouseListener specifies five methods that must be implemented by a mouse listener's class. These methods have the following signatures:

 public abstract void mouseClicked (MouseEvent e) public abstract void mouseEntered (MouseEvent e) public abstract void mouseExited (MouseEvent e) public abstract void mousePressed (MouseEvent e) public abstract void mouseReleased (MouseEvent e) 

The mouseClicked method is called when a user clicks a mouse button (that is, when a mouse button is pressed and then released). The mouseEntered method is called when the mouse pointer first enters the boundaries of a component and the mouseExited method is called when the mouse pointer leaves these boundaries. The mousePressed method is called when a user presses a mouse button and the mouseReleased method is called when this button is released.

To register with a mouse source, a mouse listener must call the source's addMouseListener method. (To de-register, a mouse listener would call the source's removeMouseListener method.)

MouseMotionListener specifies two methods that must be implemented by a mouse listener's class. These methods have the following signatures:

 public abstract void mouseDragged (MouseEvent e) public abstract void mouseMoved (MouseEvent e) 

The mouseDragged method is called when the mouse moves while one of its buttons is pressed. The source of this event is the component that lies under the mouse pointer. The mouseMoved method is called when the mouse moves within the bounding area of a component (and no mouse button is pressed).

To register with a mouse motion source, a mouse listener must call the source's addMouseMotionListener method. (To de-register, a mouse listener would call the source's removeMouseMotionListener method.)

Listing 14.20 presents the source code to a MouseListenerDemo application that demonstrates listening for mouse events. (Press Ctrl+C, or the equivalent, to terminate this program.)

Listing 14.20 The MouseListenerDemo Application Source Code
 // MouseListenerDemo.java import java.awt.*; import java.awt.event.*; class MouseListenerDemo extends Frame                         implements MouseListener, MouseMotionListener {    PopupMenu popup;    MouseListenerDemo (String title)    {       super (title);       popup = new PopupMenu ("Hello");       popup.add (new MenuItem ("First"));       popup.add (new MenuItem ("Second"));       popup.addSeparator ();       popup.add (new MenuItem ("Third"));       add (popup);       addMouseListener (this);       addMouseMotionListener (this);       setSize (100, 100);       setVisible (true);    }    public void mouseEntered (MouseEvent e)    {       System.out.println ("Mouse Entered");    }    public void mouseExited (MouseEvent e)    {       System.out.println ("Mouse Exited");    }    public void mousePressed (MouseEvent e)    {       System.out.println ("Mouse Pressed");       if (e.isPopupTrigger ())           popup.show (e.getComponent (), e.getX (), e.getY ());    }    public void mouseReleased (MouseEvent e)    {       System.out.println ("Mouse Released");       if (e.isPopupTrigger ())           popup.show (e.getComponent (), e.getX (), e.getY ());    }    public void mouseClicked (MouseEvent e)    {       System.out.println ("Mouse Clicked");    }    public void mouseMoved (MouseEvent e)    {       System.out.println ("Mouse Moved");    }    public void mouseDragged (MouseEvent e)    {       System.out.println ("Mouse Dragged");    }    public static void main (String [] args)    {       new MouseListenerDemo ("Mouse Listener Demo");    } } 

MouseListenerDemo sends messages to the standard output device when mouse events occur. You'll notice that code to detect whether a user has triggered a pop-up menu is placed in both the mousePressed and mouseReleased methods. When run under Windows 98, a pop-up menu is triggered by a mouse button release. Therefore, e.isPopupTrigger returns true when called from the mouseReleased method. (It does not return true when called from mousePressed. ) Under another operating system, a pop-up menu might be triggered by a mouse button press instead of a mouse button release. Therefore, to achieve portability, it is a good idea to place pop-up menu triggering code in both methods.

Text Listeners

Text listeners listen for text events. They are represented by objects implementing the TextListener interface (located in the java.awt.event package).

TextListener specifies a single method that must be implemented by a text listener's class. This method has the following signature:

 public abstract void textValueChanged (TextEvent e) 

The textValueChanged method is called when a text component's contents are changed as a user types or when the setText method is called to specify this text.

To register with a text source, a text listener must call the source's addTextListener method. (To de-register, a text listener would call the source's removeTextListener method.)

Listing 14.21 presents the source code to a TextListenerDemo application that demonstrates listening for text events. (Press Ctrl+C, or the equivalent, to terminate this program.)

Listing 14.21 The TextListenerDemo Application Source Code
 // TextListenerDemo.java import java.awt.*; import java.awt.event.*; class TextListenerDemo extends Frame implements TextListener {    TextListenerDemo (String title)    {       super (title);       Panel p = new Panel ();       p.setLayout (new FlowLayout (FlowLayout.LEFT));       p.add (new Label ("Please enter a name (8 chars maximum):"));       TextField nameField = new TextField (10);       nameField.addTextListener (this);       p.add (nameField);       add (p, "North");       setSize (400, 100);       setVisible (true);    }    public void textValueChanged (TextEvent e)    {       TextField tf = (TextField) e.getSource ();       String text = tf.getText ();       if (text.length () > 8)       {           int cp = tf.getCaretPosition ();           tf.setText (text.substring (0, text.length ()  1));           tf.setCaretPosition (cp);       }    }    public static void main (String [] args)    {       new TextListenerDemo ("Text Listener Demo");    } } 

TextListenerDemo displays a GUI consisting of a single label and a text field. As a user types, text events are generated and the textValueChanged method is called. The current text is retrieved and its length is compared to a maximum of eight. If the length exceeds this limit, the last character of text is removed, and the text field is reset to all characters except this character. The caret position is preserved so that a user can continue typing from where he left off.

Troubleshooting Tip

Sometimes, you might want to restrict the actual characters that a user can type. For example, you might want to prevent a user from entering lowercase letters . If you aren't sure how to solve this problem, see "Restricting Text Characters" in the "Troubleshooting" section at the end of this chapter.


Window Listeners

Window listeners listen for window events. These events include opening a window, closing a window, window closed, iconifying a window, deiconifying a window, activating a window, and deactivating a window. Each window listener is represented by an object that implements the WindowListener interface (located in the java.awt.event package).

WindowListener specifies seven methods that must be implemented by a window listener's class. These methods have the following signatures:

 public abstract void windowOpened (WindowEvent e) public abstract void windowClosing (WindowEvent e) public abstract void windowClosed (WindowEvent e) public abstract void windowIconified (WindowEvent e) public abstract void windowDeiconified (WindowEvent e) public abstract void windowActivated (WindowEvent e) public abstract void windowDeactivated (WindowEvent e) 

The windowOpened method is called when a window is initially opened. When a user tries to close a window, windowClosing is called. The windowClosed method is called after the window has closed. When a window is being iconified (minimized), the windowIconified method is called. When a user deiconifies the window (by returning it to its normal size ), windowDeiconified is called. The windowActivated method is called when the window is brought to the front of a stack of windows. Finally, when the window is removed from the front (through iconfication, closing, or another window becoming activated), windowDeactivated is called.

To register with a window source, a window listener must call the source's addWindowListener method. (To de-register, a window listener would call the source's removeWindowListener method.)

Listing 14.22 presents the source code to a WindowListenerDemo application that demonstrates listening for window events.

Listing 14.22 The WindowListenerDemo Application Source Code
 // WindowListenerDemo.java import java.awt.*; import java.awt.event.*; class WindowListenerDemo extends Frame implements WindowListener {    WindowListenerDemo (String title)    {       super (title);       addWindowListener (this);       setSize (100, 100);       setVisible (true);    }    public void windowOpened (WindowEvent e)    {       System.out.println ("window opened");    }    public void windowClosing (WindowEvent e)    {       System.out.println ("window closing");       dispose ();    }    public void windowClosed (WindowEvent e)    {       System.out.println ("window closed");       System.exit (0);    }    public void windowIconified (WindowEvent e)    {       System.out.println ("window iconified");    }    public void windowDeiconified (WindowEvent e)    {       System.out.println ("window deiconified");    }    public void windowActivated (WindowEvent e)    {       System.out.println ("window activated");    }    public void windowDeactivated (WindowEvent e)    {       System.out.println ("window deactivated");    }    public static void main (String [] args)    {       new WindowListenerDemo ("Window Listener Demo");    } } 

WindowListenerDemo sends messages to the standard output device (via window listener method calls when window events occur) in a certain order. For example, under Windows 98, the following order is observed : When a window is first displayed, windowActivated is called followed by windowOpened. When the window is iconified, windowIconified is called followed by windowDeactivated. When the window is deiconified, windowActivated is called, followed by windowDeiconified, followed by windowActivated. When another window is moved over WindowListenerDemo 's window, windowDeactivated is called. When WindowListenerDemo 's window is brought back to the front, windowActivated is called. Finally, when the user selects the window's close box, windowClosing is called, followed by windowClosed.

Placing a System.exit call in windowClosing would not cause the windowClosed method to be called. If you want this method called, you should call dispose from windowClosing. You can then call System.exit from windowClosed. (If you are not concerned with any code being executed in windowClosed, you can call System.exit from windowClosing ”which is done by most of the programs in this chapter.)

The dispose method is also useful for closing dialog windows in response to a user pressing some appropriate button (such as OK or Cancel ). This behavior can be demonstrated by the DisposeDialogDemo application, whose source code is presented in Listing 14.23.

Listing 14.23 The DisposeDialogDemo Application Source Code
 // DisposeDialogDemo.java import java.awt.*; import java.awt.event.*; class DisposeDialogDemo {    public static void main (String [] args)    {       Frame f = new Frame ("Dialog Demo");       f.setSize (200, 100);       f.setVisible (true);      AreYouSure ays = new AreYouSure (f, "Is the sky blue?");      if (ays.getState () == true)           System.out.println ("Yes, the sky is blue.");       else           System.out.println ("No, the sky is not blue.");      System.exit (0);    } } class AreYouSure extends Dialog implements ActionListener {    private boolean state;    AreYouSure (Frame f, String title)    {       super (f, title, true); // Ensure dialog is modal       Panel p = new Panel ();       Button b = new Button ("Yes");       b.addActionListener (this);       p.add (b);       b = new Button ("No");       b.addActionListener (this);       p.add (b);       add (p);       setSize (200, 100);       setResizable (false);       setVisible (true);    }    public void actionPerformed (ActionEvent e)    {       if (e.getActionCommand ().equals ("Yes"))           state = true;       else           state = false;       dispose ();    }    public boolean getState ()    {       return state;    } } 

If you look carefully at the source code, you'll see that this program exits via a call to System.exit. This method is required in DisposeDialogDemo for the same reason that it was required in SystemInfo, MangledButton, and WindowListenerDemo ”the background AWT threads must be terminated before the program can exit.

Note

When you run DisposeDialogDemo, you'll discover that its parent frame is also displayed, even though the frame's setVisible method wasn't called. This proves that a container is also made visible when one of its contained components is made visible. (When you run this program, you might have to move the dialog so you can see the parent frame.)


Adapters

Suppose you are implementing MouseListener, WindowListener, or another listener interface with more than one method. It can be a real pain to have to implement those methods that aren't going to be used. (You end up stubbing out these other methods.) The windowing toolkit has a solution to this problem ”adapters.

An adapter is a class that implements a listener interface. All methods in this class are stubbed out. To use an adapter, you must create a subclass and override the method (or methods) of interest. You then create an object from your subclass and pass its reference to an appropriate registration method.

Listing 14.24 presents the source code to a WindowAdapterDemo1 application that demonstrates listening for window closing events (only), via an object created from a subclass of WindowAdapter.

Listing 14.24 The WindowAdapterDemo1 Application Source Code
 // WindowAdapterDemo1.java import java.awt.*; import java.awt.event.*; class myWindowAdapter extends WindowAdapter {    public void windowClosing (WindowEvent e)    {       System.exit (0);    } } class WindowAdapterDemo1 extends Frame {    WindowAdapterDemo1 (String title)    {        super (title);       myWindowAdapter mwa = new myWindowAdapter ();       addWindowListener (mwa);       setSize (100, 100);       setVisible (true);    }    public static void main (String [] args)    {       new WindowAdapterDemo1 ("Window Adapter Demo1");    } } 

Caution

When working with adapters, be sure to specify the exact signature(s) of the method(s) being overridden. If you don't specify an exact signature, the compiler will "think" you've created a new method, instead of overriding an inherited method. The compiler won't warn you, and the only way you'll know that something is wrong is when your program doesn't work as expected. For example, in WindowAdapterDemo1 's, myWindowAdapter class, windowClosing is overridden. If this method had been spelled WindowClosing, the compiler would not have overridden windowClosing. Instead, it would have introduced a new method called WindowClosing. The only way you would know about this problem is when you tried to close the window, and found out that it wouldn't close.


Having to introduce a new class and figure out a name that does not conflict with an existing class name can be bothersome. In this kind of situation, you can use an anonymous inner class. Listing 14.25 presents the source code to a WindowAdapterDemo2 application that demonstrates listening for window closing events (only), via an object created from an anonymous subclass of WindowAdapter.

Listing 14.25 The WindowAdapterDemo2 Application Source Code
 // WindowAdapterDemo2.java import java.awt.*; import java.awt.event.*; class WindowAdapterDemo2 extends Frame {    WindowAdapterDemo2 (String title)    {       super (title);       addWindowListener (new WindowAdapter ()                          {                              public void windowClosing (WindowEvent e)                              {                                 System.exit (0);                              }                          });       setSize (100, 100);       setVisible (true);    }    public static void main (String [] args)    {       new WindowAdapterDemo2 ("Window Adapter Demo2");    } } 
   


Special Edition Using Java 2 Standard Edition
Special Edition Using Java 2, Standard Edition (Special Edition Using...)
ISBN: 0789724685
EAN: 2147483647
Year: 1999
Pages: 353

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net