Blakes 21 Days Chapter 12 Document
Day 12, Responding to User Input
- Top
- 339 Designing a Java program with a graphical user interface (GUI) isn't very useful if the user can't do anything about it.
- To make the program completely functional, you must make sure the interface receptive to user events.
- 339 Swing handles events with a set of interfaces called event listeners.
- You create a listener object and associate it with the user interface component being monitored.
- 339 Today, you learn how to add listeners of all kinds to your Swing programs,
- including those that handle action events, mouse events, and other interaction.
- 339 When you're finished, you will have created a full Java application using the Swing set of classes
Event Listeners
- Top
- 340 If a class wants to respond to a user event in Java, it must implement the interface that deals with events.
- This interface is not the same thing as a GUI.
- The interface is an abstract type that defines methods a class must implement.
- 340 Interfaces that handle user events are called event listeners.
- 340 Each listener handles a specific kind of event.
- Top
- 340 The java.awt.event package contains all the basic event listeners, as well as the objects that represent specific events.
- These listener interfaces are some of the most useful:
- ActionListener - Action events, which are generated when a user performs an action on a component, such as clicking a button
- AdjustmentListener - Adjustment events, which are generated when a component is adjusted, such as when a scrollbar is moved
- FocusListener - Keyboard focus event, which are generated when a component such as a text field gains or loses the focus
- ItemListener - Item events, which are generated when an item such as a check box is changed
- KeyListener - Keyboard events, which occur when a user enters text using the keyboard
- MouseListener - Mouse events, which are generated by mouse clicks, a mouse entering a component's area, and a mouse leaving a component's area
- MouseMotionListener - Mouse movement events, which track all movement by a mouse over a component
- WindowListener - Window events, which are generated when a window is maximized, minimized, moved, or closed
- Top
- 340 Just as Java class can implement multiple interfaces, a class that takes user input can implement as many listeners as needed.
- The implements keyword in the class declaration is followed by the name of the interface.
- If more than one interface has been implemented, their names are separated by commas.
- 340 The following class is declared to handle both action and text events:
public class Suspense extends JFrame implements ActionListener,
TextListener {
// body of class
}
- 341 To refer to these event listener interfaces in your programs,
- you can import them individually or use an import statement with a wildcard to make the entire package available:
- import java.awt.*;
Setting Up Components
- Top
- 341 When you make a class an event listener, you have set up a specific type of event to be heard by that class.
- However, the event won't be heard unless you follow up with a second step:
- You must add a matching listener to the GUI component.
- That listener generates the events when the component is used.
- 341 After a component is created, you can call one (or more) of the following methods on the component to associate a listener with it:
- addActionListener() - JButton, JCheckBox, JComboBox, JTextField, JRadioButton, and JMenuItem components
- addFocusListener() - All Swing components
- addItemListener() - JButton, JCheckBox, JComboBox, and JRadioButtoncomponents
- addKeyListener() - All Swing components
- addMouseListener() - All Swing components
- addMouseMotionListener() - All Swing components
- addTextListener() - JTextField and JTextArea components
- addWindowListener() - JWindow and JFrame components
- Top
- 341 CAUTION - Modifying a component after adding it to a container is an easy mistake to make in a Java program.
- You must add listeners to a component and handle any other configuration before the component is added to any containers,
- otherwise, these settings are disregarded when the program is run.
- Top
- 341 The following example creates a JButton object and associates an action event listener with it:
JButton zap = new JButton("Zap");
zap.addActionListener(this);
- 342 All the listener adding methods take one argument: the object that is listening for events of that kind.
- Using this indicates that the current class is the event listener.
- You could specify a different object, as long as its class implements the right listener interface.
Event-Handling Methods
- Top
- 342 When you associate an interface with a class, the class must contain methods that implement every method in the interface.
- 342 In the case of event listeners, the windowing system calls each method automatically when the corresponding user event takes place.
- 342 The ActionListener interface has only one method: actionPerformed().
- All classes that implement ActionListener must have a method with the following structure:
public void actionPerformed(ActionEvent event) {
// handle event here
}
- Top
- 342 If only one component in your program's GUI has a listener for action events,
- you will know that this actionPerformed() method is called only in response to an event generated by that component.
- 342 This makes it simpler to write the actionPerformed() method.
- All the method's code responds to that component's user event.
- 342 But when more than one component has an action event listener,
- you must use the method's ActionEvent argument to figure out which component was used and act accordingly in your program.
- You can use this object to discover details about the component that generated the event.
- 342 ActionEvent and all other event objects are part of the java.awt.event package.
- Top
- 342 Every event-handling method is sent an event object of some kind.
- You can use the object's getSource() method to determine which component sent the event, as in the following example:
public void actionPerformed(ActionEvent event) {
Object source = evt.getSource();
}
- 342 The object returned by the getSource() method can be compared to components by using the == operator.
- The following statements extend the preceding example to handle user clicks on buttons named quitButton and sortRecords:
if(source == quitButton) {
quit();
}
if(source == sortRecords) {
sort();
}
- Top
- 343 The quit() method is called if the quitButton object generated the event,
- and the sort() method is called if the sortRecords button generated the event.
- 343 Many event-handling methods call a different method for each kind of event or component.
- This makes the event-handling method easier to read.
- In addition, if a class has more than one event-handling method, each one can call the same methods to get work done.
- 343 Java's instanceof operator can be used in an event-handling method to determine the class of component that generated the event.
- The following example can be used in a program with one button and one text field, each of which generates an action event:
void actionPerformed(ActionEvent event) {
Object source = event.getSource();
if(source instanceof JTextField) {
calculateScore();
} else if (source instanceof JButton) {
quit();
}
}
- Top
- 343 If the event-generating component belongs to the JTextField class, the calculateScore() method is called.
- If the component belongs to JButton, the quit() method is called instead.
First Program
- Top
- 343 The TitleBar application, shown in Listing 12.1, displays a frame with two JButton components, which are used to change the text on the frame's title bar.
- Create a new empty Java file called TitleBar, assign it the package com.java21days, and enter the class's sorce code
Listing 12.1 The Full Text of TitleBar.java
- Top
- page 343-344
package com.java21days;
import java.awt.event.*;
import javax.swing.*;
import java.awt.*
public class TitleBar extends JFrame implements ActionListener {
JButton b1;
JButton b2;
public TitleBar() {
super("Title Bar");
setDefaultCloseOperation(JFRame.EXIT_ON_CLOSE);
setLookAndFeel();
b1 = new JButton("Rosencrantz");
b2 = new JButton("Guildenstern");
b1.addActionListener(this);
b2.addActionListener(this);
FlowLayout flow = new FlowLayout();
setLayout(flow);
add(b1);
add(b2);
pack();
setVisible(true);
}
public void actionPerformed(ActionEvent evt) {
Object source = evt.getSource();
if (source == b1) {
setTitle("Rosencrantz");
} else if (source == b2) {
setTitle("Guildenstern");
}
repaint();
}
private void setLookAndFeel() {
try {
UIManager.setLookAndFeel(
"com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"
);
SwingUtilities.updateComponentTreeUI(this);
} catch(Exception exc) {
System.err.println("Couldn't use the system "
+ "look and feel: " + exc);
}
}
public static void main(String[] arguments) {
TitleBar frame = new TitleBar();
}
}
The Explanation
- Top
- 344 After you run this application with the Java Virtual Machine (JVM), the program's interface should resemble Figure 12.1
Figure 12.1 - The TitleCar application. - goes here
- Top
- 345 Only 13 lines are needed to respond to action events in this application:
- Line 3 imports the java.awt.event package.
- Line 7 indicates the class implements the ActionListener interface.
- Lines 17 - 18 add action listeners to both JButton objects.
- Lines 27 - 35 respond to action events that occur from the two JButton objects.
- The evt object's getSource() method determines the event's source.
- If it is equal to the b1 button, the frame's title is set to Rosencrantz,
- if it is equal to b2, the title is set to Guildenstern.
- A call to repaint() is needed so that the frame is redrawn after any title change that might have occured in the method.
Working with Methods
- Top
- 345 The following sections detail the structure of each event-handling method and the methods that can be used within them.
- 345 In addition to the methods described, the getSource() method can be used on any event object to determine which object generated the event.
Action Events
- Top
- 345 Action events occur when a user completes an action using components such as buttons, check boxes, menu items, text fields, and radio buttons.
- 345 A class must implement the ActionListener interface to handle these events.
- In addition, the addActionListener() method must be called on each component that should generate an action event,
- unless you want to ignore that component's action events.
- 345 The actionPerformed(ActionEvent) method is the only method of the ActionListener interface.
- It takes the following form:
public void actionPerformed(ActionEvent event) {
// ...
}
- Top
- 345 In addition to the getSource() method,
- you can use the getActionCommand() method on the ActionEvent object to discover more information about the event's source.
- 346 By default, the action command is the text associated with the component, such as the label on a button.
- You also can set a different action command for a component by calling it's setActionCommand(String) method.
- The string argument should be the action command's desired text.
- 346 The following statements create a button and menu item and give both of them the action command "Sort Files":
JButton sort = new JButton("Sort");
JMenuItem menuSort = new JMenuItem("Sort");
sort.setActionCommand("Sort Files");
menuSort.setActionCommand("Sort Files");
- Top
- 346 TIP: Action commands are useful in a program in which more than one component should cause the same thing to happen.
- By giving both components the same action command, you can handle them with the same code in an event-handling method.
Focus Events
- Top
- 346 Focus events occur when any component gains or loses input focus on a GUI.
- Focus describes the component that is active for keyboard input.
- If one of the fields has the focus (in a user interface with several editable text fields), the cursor blinks in the field.
- Any text entered goes into this component.
- 346 Focus applies to all components that can receive input.
- You can give a component the focus by calling its requestFocus() method with no arguments, as in this example:
JButton ok = new JButton("OK");
ok.requestFocus();
- 346 To handle a focus event, a class must implement the FocusListener interface,
- which has two methods: focusGained(FocusEvent) and focusLost(FocusEvent).
- They take the following forms:
public void focusGained(FocusEvent event) {
// ...
}
public void focusLost(FocusEvent event) {
// ...
}
- Top
- 347 To determine which object gained or lost the focus,
- the getSource() method can be called on the FocusEvent object sent as an argument to the two methods.
Second Program
- Top
- 347 Listing 12.2 contains Calculator, a Java application that displays the sum of two numbers.
- Focus events are used to determine when the sum needs to be recalculated.
- 347 In NetBeans create a new Java file with the name Calculator and package name com.java21days with the sorce code of this listing.
Listing 12.2 The Full Text of Calculator.java
- Top
- page 347-348
package com.java21days;
import java.awt.event.*;
import javax.swing.*;
import java.awt.*
public class Calculator extends JFrame implements FocusListener {
JTextField value1, value2, sum;
JLabel plus, equals;
public Calculator() {
super("Add Two Numbers");
setSize(350, 90);
setDefaultCloseOperation(JFRame.EXIT_ON_CLOSE);
setLookAndFeel();
FlowLayout flow = new FlowLayout(FlowLayout.CENTER);
setLayout(flow);
// create components
value1 = new JTextField("0", 5);
plus = new JLabel("+");
value2 = new JTextField("0", 5);
equals = new JLabel("=");
sum = new JTextField("0", 5);
// add listeners
value1.addFocusListener(this);
value2.addFocusListener(this);
// set up sum field
sum.setEditable(false);
// add components
add(value1);
add(plus);
add(value2);
add(equals);
add(sum);
setVisible(true);
}
public void focusGained(FocusEvent event) {
try{
float total = Float.parseFloat(value1.getText()) +
Float.parseFloat(value2.getText());
sum.setText("" + total);
} catch (NumberFormatException nfe) {
value1.setText("0");
value2.setText("0");
sum.setText("0");
}
}
public void focusLost(FocusEvent event) {
focusGained(event);
}
private void setLookAndFeel() {
try {
UIManager.setLookAndFeel(
"com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"
);
SwingUtilities.updateComponentTreeUI(this);
} catch(Exception exc) {
System.err.println("Couldn't use the system "
+ "look and feel: " + exc);
}
}
public static void main(String[] arguments) {
Calculator frame = new Calculator();
}
}
The Explanation
- Top
- 348 Figure 12.2 shows the application
Figure 12.2 - The Calculator application - goes here
- Top
- 348 In this application, focus listeners are added to the first two text fields, value1 and value2, and the class implements the FocusListener interface.
- 348 The focusGained() method is called whenever either of these fields gains the input focus (lines 38 - 48).
- In this method, the sum is calculated by adding the values in the other two fields.
- If either field contains an invalid value, such as a string, a NumberFormatException is thrown, and all three fields are reset to "0".
- 349 The focusLost() method accomplishes the same behavior by calling focusGained() with the focus event as an argument.
- 349 One thing to note about this application is that event-handling behavior is not required to collect numeric input in a text field.
- This is taken care of automatically by any component in which text input is received.
Item Events
- Top
- 349 Item events occur when an item is selected or deselected on components such as buttons, check boxes, or radio buttons.
- A class must implement the ItemListener interface to handle these events.
- 349 The itemStateChanged(ItemEvent) method is the only method in the ItemListener interface.
- It takes the following form:
void itemStateChanged(ItemEvent event) {
// ...
}
- Top
- 349 To determine in which item the event occured, the getItem() method can be called on the ItemEvent object.
- 349 You also can see whether the item was selected or deselected by using the getStateChanged() method.
- This method returns an integer that equals either the class variable ItemEvent.DESELECTED or ItemEvent.SELECTED.
Third Program
- Top
- 349 The FormatChooser application, shown in Listing 12.3, illustrates the use of item events,
- displaying information about a selected combo box item in a label.
- 349 Create it with NetBeans as an empty Java file with the class name FormatChooser and package name com.java21days.
Listing 12.3 The Full Text of FormatChooser.java
- Top
- page 349-350
package com.java21days;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class FormatChooser extends JFrame implements ItemListener {
String[] formats = { "(choose format)", "Atom", "RSS 0.92",
"RSS 1.0", "RSS 2.0" };
String[] descriptions = {
"Atom weblog and syndication format",
"RSS syndication format 0.92 (Netscape)",
"RSS/RDF syndication format 1.0 (RSS/RDF)",
"RSS syndication format 2.0 (UserLand)"
};
JComboBox formatBox = new JComboBox();
JLabel descriptionLabel = new JLabel("");
public FormatChooser() {
super("Syndication Format");
setSize(420, 150);
setDefaultCloseOperation(JFRame.EXIT_ON_CLOSE);
setLayout(new BorderLayout());
for (int i = 0; i < formats.length; i++) {
formatBox.addItem(formats[i]);
}
formatBox.addItemListener(this);
add(BorderLayout.NORTH, formatBox);
add(BorderLayout.CENTER, descriptionLabel);
setVisible(true);
}
public void itemStateChanged(ItemEvent event) {
int choice = formatBox.getSelectedIndex();
if (choice > 0) {
descriptionLabel.setText(descriptions[choice-1]);
}
}
public Insets getInsets() {
return new Insets(50, 10, 10, 10);
}
private static void setLookAndFeel() {
try {
UIManager.setLookAndFeel(
"com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"
);
} catch(Exception exc) {
System.err.println("Couldn't use the system "
+ "look and feel: " + exc);
}
}
public static void main(String[] arguments) {
FormatChooser.setLookAndFeel();
FormatChooser fc = new FormatChooser();
}
}
The Explanation
- Top
- 350 This application extends the combo box example from Day 9, "Working with Swing."
- Figure 12.3 shows how it looks after a choice has been made.
Figure 12.3 - The output of the FormatChooser application - goes here
- Top
- 351 The application creates a combo box from an array of strings and adds an item listener to the component (lines 24 - 27).
- Item events are received by the itemStateChanged(ItemEvent) method (lines 33 - 38),
- which changes a label's text based on the index number of the selected item.
- Index 1 corresponds with "Atom", 2 with "RSS 0.92", 3 with "RSS 1.0", and 4 with "RSS 2.0".
Key Events
- Top
- 351 Key events occur when a key is pressed on the keyboard.
- Any component can generate these events. and a class must implement the KeyListener interface to support them.
- 351 The KeyListener interface has three methods:
- keyPressed(KeyEvent)
- keyReleased(KeyEvent)
- keyTyped(KeyEvent)
- Top
- 351 They take the following forms:
public void keyPressed(KeyEvent event) {
// ...
}
public void keyReleased(KeyEvent event) {
// ...
}
public void keyTyped(KeyEvent event) {
// ...
}
- Top
- 351 KeyEvent's getKeyChar() method returns the character of the key associated with the event.
- If no Unicode character can be represented by the key, getKeyChar() returns a character value equal to the class variable KeyEvent.CHAR_UNDEFINED.
- 351 For a component to generate key events, it must be able to receive the input focus.
- Text fields, text areas, and other components that accept keyboard input, support this capability automatically.
- For other components, such as labels and panels, the setFocusable(boolean) method should be called with an argument of true, as in the following code:
- JPanel pane = new JPanel();
pane.setFocusable(true);
Mouse Events
- Top
- 352 Mouse events are generated by a mouse click, a mouse entering a component's area, or a mouse leaving the area.
- Any component can generate these events, which are implemented by a class through the MouseListener interface,
- which has five methods:
- mouseClicked(MouseEvent)
- mouseEntered(MouseEvent)
- mouseExited(MouseEvent)
- mousePressed(MouseEvent)
- mouseReleased(MouseEvent)
- Each method takes the same basic form as mouseReleased(MouseEvent):
- public void mouseReleased(MouseEvent event) {
// ...
}
- Top
- 352 The following methods can be used on MouseEvents objects:
- getClickCount() - Returns as an integer the number of times the mouse was clicked
- getPoint() - Returns as a Point object the (x,y) coordinate within the component where the mouse was clicked
- getX() - Returns the x position
- getY() - Returns the y position
Mouse Motion Events
- Top
- 352 Mouse motion events occur when the mouse is moved over a component.
- As with other mouse events, any component can generate mouse motion events.
- A class must implement the MouseMotionListener interface to support them.
- 353 The MouseMotionListener interface has two methods:
- mouseDragged(MouseEvent)
- mouseMoved(MouseEvent)
- 353 They take the following forms:
public void mouseDragged(MouseEvent event) {
// ...
}
public void mouseMoved(MouseEvent event) {
// ...
}
- Top
- 353 Unlike the other event-listener interfaces you have delt with up to this point,
- MouseMotionListener does not have its own event type.
- Instead, MouseEvent objects are used.
- 353 Because of this, you can call the same methods you would for mouse events:
- getClick()
- getPoint()
- getX()
- getY()
Fourth Program
- Top
- 353 The next project you will undertake demonstrates how to detect and respond to mouse events.
- The MousePrank application, shown in Listing 12.4, consists of two classes, MousePrank and PrankPanel1,
- that implement a user interface button that tries to avoid being clicked.
- 353 Create a new empty Java file in NetBeans with the class name MousePrank and package name com.java21days,
- then enter the code shown in Listing 12.4
- The techniques demonstrated in this class will be described after you create the application and see how it runs.
Listing 12.4 The Full Text of MousePrank.java
- Top
- page 353-355
package com.java21days;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class MousePrank extends JFrame implements ActionListener {
public MousePrank() {
super("Message");
setDefaultCloseOperation(JFRame.EXIT_ON_CLOSE);
setSize(420, 220);
BorderLayout border = new BorderLayout();
setLayout(border);
JLabel msg = new JLabel("Click OK to close program.");
add(BorderLayout.NORTH, msg);
PrankPanel prank = new PrankPanel();
prank.ok.addActionListener(this);
add(BorderLayout.CENTER, prank);
setVisible(true);
}
public void actionPerformed(ActionEvent event) {
System.exit(0);
}
public Insets getInsets() {
return new Insets(40, 10, 10, 10);
}
private static void setLookAndFeel() {
try {
UIManager.setLookAndFeel(
"com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"
);
} catch(Exception exc) {
System.err.println("Couldn't use the system "
+ "look and feel: " + exc);
}
}
public static void main(String[] arguments) {
MousePrank.setLookAndFeel();
new MousePrank();
}
}
class PrankPane1 extends JPanel implements MouseMotionListener {
JButton ok = new JButton("OK");
int buttonX, buttonY, mouseX, mouseY;
int width, height;
PrankPanel() {
super();
setLayout(null);
addMouseMotionListener(this);
buttonX = 110;
buttonY = 110;
ok.setBounds(new Rectangle(buttonX, buttonY,
70, 20));
add(ok);
}
public void mouseMoved(MouseEvent event) {
mouseX = event.getX;
mouseY = event.getY;
width = (int) getSize().getWidth();
height = (int) getSize().getHeight();
if (Math.abs((mouseX + 35) - buttonX) < 50 {
buttonX = moveButton(mouseX, buttonX, width);
repaint();
}
if (Math.abs((mouseY + 10) - buttonX) < 50 {
buttonY = moveButton(mouseY, buttonY, height);
repaint();
}
}
public void mouseDragged(MouseEvent event) {
// ignore this event
}
private int moveButton(int mouseAt, int buttonAt, int bord) {
if (buttonAt < mouseAt) {
buttonAt--;
} else {
buttonAt++;
}
if (buttonAt > (bord - 20)) {
buttonAt = 10;
}
if (buttonAt < 0) {
buttonAt = bord - 80;
}
return buttonAt;
}
public void paintComponent(Graphics comp) {
super.paintComponent(comp);
ok.setBounds(buttonX, buttonY, 70, 20);
}
}
The Explanation
- Top
- 355 The MousePrank class is a frame that holds two components arranged with a border layout,
- the label "Click OK to close this program." and a panel with an OK button on it.
- 355 Figure 12.4 shows the user interface for this application.
Figure 12.4 - The running MousePrank application - goes here
- Top
- 356 Because the button does not behave normally, it is implemented with the PrankPanel1 class, a subclass of JPanel.
- This panel includes a button that is drawn at a specific position on the panel
- instead of being placed by a layout manager.
- This technique was described at the end of Day 11, "Arranging Components on a User Interface".
- 356 First, the panel's layout manager is set to null,
- which causes it to stop using flow layout as its default manager:
- setLayout(null);
- 356 Next, the button is placed on the panel using setBounds(Rectangle),
- the same method that determines where a frame or window will appear on a desktop.
- Top
- 356 A Rectangle object is created with four arguments:
- its x position
- its y position
- width
- height
- Here's how PrankPanel draws the button:
JButton ok = new JButton("OK");
int buttonX = 110;
int buttonY = 110;
ok.setBounds(new Rectangle(buttonX, buttonY, 70, 20));
- Top
- 356 Creating the Rectangle object as the argument to setBounds()
- is more efficient than creating an object with a name and using that object as the argument.
- You don't need to use the object anywhere else in the class, so it doesn't need a name.
- The following statements accomplish the same thing in two steps:
Rectangle box = new Rectangle(buttonX, buttonY, 70, 20);
ok.setBounds(box);
- 356 The class has instance variables that hold the button's (x,y) position, buttonX and buttonY.
- They start out at (110,110) and change whenever the mouse comes within 50 pixels of the center of the button.
- 356 You track the mouse movements by implementing the MouseListener interface and its two methods,
- mouseMoved(MouseEvent) and mouseDragged(MouseEvent).
- 356 The panel uses mouseMoved() and ignores mouseDragged().
- 356 When the mouse moves, a mouse event object's getX() and getY() methods return its current (x,y) position,
- which is stored in the instance variables mouseX and mouseY.
- 356 The moveButton(int, int, int) method takes three arguments:
- The button's x or y position
- The mouse's x or y position
- The panel's width or hight
- Top
- 357 This method moves the button away from the mouse in either a vertical or horizontal direction,
- depending on whether it is called with x-cooridinates and the panel height or y-cooridinates and the width.
- 357 After the button's position has moved, the repaint() method is called,
- which causes the panel's paintComponent(Graphics) method to be called in lines 97 - 100.
- 357 Every component has a paintComponent() method that can be overridden to draw the cpmponent.
- The button's setBounds() method displays it at the current (x,y) position in line 99.
Window Events
- Top
- 357 Window events occur when a user opens or closes a window object, such as a JFrame or JWindow.
- Any component can generate these events, and a class must implement the WindowListener interface to support them.
- 357 The WindowListener interface has seven methods:
- windowActivated(WindowEvent)
- windowClosed(WindowEvent)
- windowClosing(WindowEvent)
- windowDeactivated(WindowEvent)
- windowDeiconified(WindowEvent)
- windowIconified(WindowEvent)
- windowOpened(WindowEvent)
- 357 They all take the same form as the windowOpened() method:
- public void windowOpened(WindowEvent event) {
// ...
}
- 357 The windowClosing() and windowClosed() methods are similar, but one is called as the window is closing and the other is called after it is closed.
- In fact, you can take action in a windowClosing() method to stop the window from being closed.
Using Adapter Classes
- Top
- 357 A Java class that implements an interface must include all its methods, even if it doesn't plan to do anything in response to some of them.
- 358 This requirement can make it necessary to add a lot of empty methods when you're working with an event-handling interface such as WindowListener,
- 358 As a convenience, Java offers adapters, Java classes that contain empty do-nothing implementations of specific interfaces.
- By subclassing an adapter class, you can implement only the event-handling methods you need by overriding those methods.
- The rest inherit those do-nothing methods.
- 358 The java.awt.event package includes FocusAdapter, KeyAdapter, MouseAdapter, MouseMotionAdapter, and WindowAdapter.
- They correspond to the expected listeners for focus, keyboard, mouse, mouse motion, and window events.
Fifth Program
- Top
- 358 Listing 12.5 is a Java application that displays the most recently pressed key, monitoring keyboard events thru a subclass of KeyAdapter.
- Enter this source code in a new empty Java class file named KeyChecker in NetBeans in the package com.java21days.
Listing 12.5 The Full Text of KeyChecker.java
- Top
- page 358-359
package com.java21days;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class KeyChecker extends JFrame {
JLabel keyLabel = new JLabel("Hit anykey");
public KeyChecker() {
super("Hit anykey");
setSize(300, 200);
setDefaultCloseOperation(JFRame.EXIT_ON_CLOSE);
setLayout(new FlowLayout(FlowLayout.CENTER));
KeyMonitor monitor = new KeyMonitor(this);
setFocusable(true);
addKeyListener(monitor);
add(keyLabel);
setVisible(true);
}
private static void setLookAndFeel() {
try {
UIManager.setLookAndFeel(
"com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"
);
} catch(Exception exc) {
System.err.println("Couldn't use the system "
+ "look and feel: " + exc);
}
}
public static void main(String[] arguments) {
KeyChecker.setLookAndFeel();
new KeyChecker();
}
}
class KeyMonitor extends KeyAdapter {
KeyChecker display;
KeyMonitor(KeyChecker display) {
this.display = display;
}
public void keyTyped(KeyEvent event) {
display.keyLabel.setText("" + event.getKeyChar());
}
}
The Explanation
- Top
- 359 The KeyChecker application is implemented as a main class of that name and a KeyMonitor helper class.
- 359 KeyMonitor is a subclass of KeyAdapter, an adapter class for keyboard events that implements the KeyListener interface.
- In lines 46 - 49, the keyTyped method overrides the same method in KeyAdapter, which does nothing.
- 359 When a key is pressed, the key is discovered by calling getKeyChar() of the user event object.
- This key becomes the text of keyLabel label in the KeyChecker class.
- This application is shown in Figure 12.5.
Figure 12.5 - The running KeyChecker application - goes here !!
Using Inner Classes
- Top
- 359 One of the challengers of taking user input in Java is to keep the code as short and simple as possible.
- The need to implement event listeners and all their methods, even for undesired input, requires a lot of coding.
- 360 In the KeyChecker application, an adapter class was used to shorten the amount of programming required to handle key events.
- 360 A technique to shorten it further would be to use inner classes, which are defined within a class, as if they were a method or variable.
- An adapter class is created as an inner class in this statement:
- KeyAdapter monitor = new KeyAdapter() {
public void keyTyped(KeyEvent event) {
keyLabel.setText("" + event.getKeyChar());
repaint();
}
};
Sixth Program
- Top
- 360 The KeyAdapter object overrides one method, keyTyped(KeyEvent), to receive keyboard input.
- The KeyChecker2 class shown in Listing 12.6 has two advantages over its predecessor.
- As you create it in NetBeans, see if you can figure out what they are.
Listing 12.6 The Full Text of KeyChecker2.java
- Top
- page 360-361
package com.java21days;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class KeyChecker2 extends JFrame {
JLabel keyLabel = new JLabel("Hit anykey");
public KeyChecker2() {
super("Hit anykey");
setSize(300, 200);
setDefaultCloseOperation(JFRame.EXIT_ON_CLOSE);
setLayout(new FlowLayout(FlowLayout.CENTER));
KeyAdapter monitor = new KeyAdapter() {
public void keyTyped(KeyEvent event) {
keyLabel.setText("" + event.getKeyChar());
repaint();
}
};
setFocusable(true);
addKeyListener(monitor);
add(keyLabel);
setVisible(true);
}
private static void setLookAndFeel() {
try {
UIManager.setLookAndFeel(
"com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"
);
} catch(Exception exc) {
System.err.println("Couldn't use the system "
+ "look and feel: " + exc);
}
}
public static void main(String[] arguments) {
KeyChecker2.setLookAndFeel();
new KeyChecker2();
}
}
The Explanation
- Top
- 361 The application functions identically to the KeyChecker version.
- 361 The advantage of this version are that it is shorter, not requiring the creation of a separate class,
- and it does not need to make use of the this variable in the inner class to be able to change the label in line 17.
- The inner class can access the variables and methods of its own class.
- 361 Inner classes also can be anonymous, which are objects of the class not assigned to a variable.
A note about the First Program - TitleBar
- Top
- 361 The TitleBar application developed today,
- which used action events to change a frame's title in response to button clicks, could be simplified by using anonymous inner classes.
- An anonymous inner class becomes the argument to the button's addActionListener() method, as you can see:
-
JButton b1;
b1.addActionListener(new ActionListener() {
public void ActionPerformed(ActionEvent evt) {
setTitle("Rosencrantz");
}
});
JButton b2;
b2.addActionListener(new ActionListener() {
public void ActionPerformed(ActionEvent evt) {
setTitle("Guildenstern");
}
});
- 361 The anonymous inner class is an object that implements the ActionListener interface.
- The object's actionPerformed() method is overridden to set the frame's title when the corresponding button is clicked.
- Because each button has its own listener, it's simpler than using one listener for multiple interface components.
- Top
- 362 Inner classes look more complicated than separate classes, but they can simplify and shorten your Java code.
Summary
- Top
- 362 Event handling is added to a GUI in Swing thru these fundamental steps
- hello
- A listener interface is added to the class that will contain the event-handling methods.
- Alistener is added to each component that will generate the events to handle.
- The methods are added, each with an EventObject class as the only argument to the method.
- Methods of that EventObject class, such as getSource(), are used to learn which component generated the event and what kind of event it was.
- 362 When you know these steps, you can work with each of the listener interfaces and event classes.
- You also can learn about new listeners as they are added to Swing with new components.
Q & A
- Top | Page 362
- Q Can a program's event-handling behavior be put into its own class instead of being included with the code that creates the interface ?
- A It can, and many programmers will tell you that this is a good way to design your programs.
- Separating interface design from your event-handling code allows you to develop the two separately.
- This makes it easier to maintain the project, related behavior is grouped and isolated from unrelated behavior.
- Q Is there a way to differentiate between the buttons on a mouseClicked() event ?
- A Yes. This feature of mouse events wasn't covered today because right and middle mouse buttons are platform-specific features
- that are unavailable on some systems where Java programs run.
- All mouse events send a MouseEvent object to their event-handling methods.
- Call the object's getModifiers() method to receive an integer value that indicates which mouse button generated the event.
- Check the value against three class varaiables.
- It equals MouseEvent.BUTTON_MASK if the left button was clicked,
- MouseEvent.BUTTON2_MASK if the middle button was clicked,
- and MouseEvent.BUTTON3_MASK if the right button was clicked.
- See MousetTest.java on the Day 12 page of the book's website at www.java21days.com
- for an example that implements this technique.
- (I couldn't find it.)
- Top
- 363 For more information, see the Java class library documentation for the MouseEvent class.
Quiz - Questions
- If you use this in a method call such as addActionListener(this), what object is being registered as a listener ?
- An adapter class
- The current class
- no class
- What is the benefit of subclassing an adapter class such as WindowAdapter (which implements the WindowListener interface) ?
- You inherit all the behavior of that class.
- The subclass automatically becomes a listener.
- You don't need to implement any WindowListener methods you won't be using.
- What kind of event is generated when you press Tab to leave a text field ?
- FocusEvent
- WindowEvent
- ActionEvent
Answers
- Top | Note A is 1, B is 2, and C is 3
- B. The current class must implement the correct listener interface and the required methods.
- C. Because most listener interfaces contain more methods than you need, using an adapter class as a superclass saves the hassle of implementing empty methods just to implement the interface.
- A. A user interface component loses focus when the user stops editing that component and moves to a different part of the interface.
Certification Practice
- Top
- 092 The following question is the kind of thing you could expect to be asked on a Java programming certification test.
- Answer it without looking at today's material or using the Java compiler to test the code.
- Given:
import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
public class Expunger extends JFrame implements ActionListener {
public boolean deleteFile;
public Expunger() {
super("Expunger");
JLabel commandLabel = new JLabel("Do you want to delete the file?");
JButton yes = new JButton("Yes");
JButton no = new JButton("No");
yes.addActionListener(this);
no.addActionListener(this);
setLayout( new BorderLayout() );
JPanel bottom = new JPanel();
bottom.add(yes);
bottom.add(no);
add("North", commandLabel);
add("South", bottom);
pack();
setVisible(true);
}
public void actionPerformed(ActionEvent evt) {
JButton source = (JButton) evt.getSource();
// answer goes here
deleteFile = true;
else
deleteFile = false;
}
public static void main(String[] arguments) {
new Expunger();
}
}
- 365 Which of the following statements should replace // answer goes here to make the application function correctly ?
- if (source instanceof JButton)
- if (source.getActionCommand().equals("yes"))
- if (source.getActionCommand().equals("Yes"))
- if (source.getActionCommand() == "Yes"
- Top
- 365 The answer is available on the book's website at www.java21days.com
Exercise
- Top
- 365 To extend your knowledge of the subjects covered today, try the following exercises:
- Create an application that uses FocusListener to in ensure that a text field's value is multiplied by -1
- and is redisplayed whenever a user changes it to a negative value.
- Create a calculator that adds or subtracts the contents of two text fields whenever the appropriated button is clicked,
- displaying the result as a label.
- Top
- 365 Exercise solutions are offered on the book's website at www.java21days.com. | Chapter 12's Page