Let's look at another simple program, SwingApplication. [1] Each time the user clicks the button (JButton), the label (JLabel) is updated.
|
Figure 97. The simple GUI of SwingApplication presents a JButton and a JLabel.
Look and Feel
Figure 98 shows three views of a GUI that uses Swing components. Each picture shows the same program but with a different look and feel.
Figure 98. Three samples of look and feel.
Swing allows you to specify which look and feel your program usesJava look and feel, CDE/Motif look and feel, Windows look and feel, and so on. The code in boldface type in the following snippet shows you how SwingApplication specifies its look and feel:
public static void main(String[] args) { try { UIManager.setLookAndFeel( UIManager.getCrossPlatformLookAndFeelClassName()); } catch (Exception e) { } ...// Create and show the GUI... }
The preceding code essentially says, "I don't care whether the user has chosen a look and feeluse the cross-platform look and feel (the Java look and feel)."
Setting Up Buttons and Labels
Like most GUIs, the SwingApplication GUI contains a button and a label. (Unlike most GUIs, that's about all that SwingApplication contains.) Here's the code that initializes the button:
JButton button = new JButton("I'm a Swing button!"); button.setMnemonic('i'); button.addActionListener(...create an action listener...);
The first line creates the button. The second sets the letter "i" as the mnemonic that the user can use to simulate a click of the button. For example, in the Java look and feel, typing Alt-i results in a button click. The third line registers an event handler for the button click, as discussed later in this section.
Here's the code that initializes and manipulates the label:
...// where instance variables are declared: private static String labelPrefix = "Number of button clicks: "; private int numClicks = 0; ...// in GUI initialization code: final JLabel label = new JLabel(labelPrefix + "0 "); ... label.setLabelFor(button); ...// in the event handler for button clicks: label.setText(labelPrefix + numClicks);
The preceding code is pretty straightforward, except for the line that invokes the setLabelFor method. That code exists solely to hint to assistive technologies that the label describes the button. [1]
[1] Assistive technologies enable people with permanent or temporary disabilities to use computers. For more information, see the section "How to Support Assistive Technologies" in the book The JFC Swing Tutorial. This section is also available on this book's CD and online at: http://java.sun.com/docs/books/tutorial/uiswing/misc/access.html
Now that you know how to set up buttons, you also know how to set up check boxes and radio buttons, as they all inherit from the AbstractButton class. Check boxes are similar to radio buttons, but by convention their selection models are different. Any number of check boxes in a groupnone, some, or allcan be selected. On the other hand, only one button can be selected from a group of radio buttons. Figure 99 shows pictures of two programs that use radio buttons and check boxes.
Figure 99. As you'd expect, the CheckBoxDemo application shows the use of check boxes, and the RadioButtonDemo application shows the use of radio buttons. Both programs are available on this book's CD and online.
You'll get a chance to take a closer look at radio buttons in the section Example Five: VoteDialog (page 368).
Handling Events
Every time the user types a character or pushes a mouse button, an event occurs. Any object can be notified of the event. All the object has to do is implement the appropriate interface and be registered as an event listener on the appropriate event source.
How to Implement an Event Handler
Every event handler requires three pieces of code:
public class MyClass implements ActionListener {
someComponent.addActionListener(instanceOfMyClass);
public void actionPerformed(ActionEvent e) { ...//code that reacts to the action... }
Event handlers can be instances of any class. Often an event handler that has only a few lines of code is implemented using an anonymous inner classan unnamed class defined inside of another class. Anonymous inner classes can be confusing at first, but once you're used to them, they make the code clearer by keeping the implementation of an event handler close to where the event handler is registered.
SwingApplication has two event handlers. One handles window closing (window events); the other handles button clicks (action events). We've already seen the window-closing code. Here is the code that handles button clicks in the SwingApplication:
button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { numClicks++; label.setText(labelPrefix + numClicks); } });
In general, to detect when the user clicks an on-screen button (or does the keyboard equivalent), a program must have an object that implements the ActionListener interface. The program must register this object as an action listener on the button (the event source), using the addActionListener method. When the user clicks the on-screen button, the button fires an action event. This results in the invocation of the action listener's actionPerformed method (the only method in the ActionListener interface). The single argument to the method is an ActionEvent object that gives information about the event and its source.
Figure 100. When the user clicks a button, the button's action listeners are notified.
Swing components can generate many kinds of events. Table 49 lists a few examples.
Act that Results in the Event |
Listener Type |
---|---|
User clicks a button, presses Return while typing in a text field, or chooses a menu item |
ActionListener |
User closes a frame (main window) |
WindowListener |
User presses a mouse button while the cursor is over a component |
MouseListener |
User moves the mouse over a component |
MouseMotionListener |
Component becomes visible |
ComponentListener |
Component gets the keyboard focus |
FocusListener |
Table or list selection changes |
ListSelectionListener |
To learn more about how to detect events from a particular component, refer to each component's how-to section in the "Creating a GUI with JFC Swing" trail. This trail is also available on the CD or online at: http://java.sun.com/docs/books/tutorial/uiswing/components/index.html.
Note
Event-handling code executes in an single thread, the event-dispatching thread. This ensures that each event handler finishes execution before the next one executes. For instance, the actionPerformed method in the preceding example executes in the event-dispatching thread. Painting code also executes in the event-dispatching thread. Therefore, while the actionPerformed method is executing, the program's GUI is frozenit won't repaint or respond to mouse clicks. See the section Threads and Swing (page 378) for more information.
Adding Borders Around Components
If you take another look at the snapshot of SwingApplication (Figure 97 on page 356), you'll notice that there is extra space surrounding the JPanel on all four edges. Here is the code that adds a border to the panel:
pane.setBorder(BorderFactory.createEmptyBorder( 30, //top 30, //left 10, //bottom 30) //right );
This border simply provides some empty space around the panel's contents30 extra pixels on the top, left, and right, and 10 extra pixels on the bottom. Borders are a feature that JPanel inherits from the JComponent class.
Getting Started
Object-Oriented Programming Concepts
Language Basics
Object Basics and Simple Data Objects
Classes and Inheritance
Interfaces and Packages
Handling Errors Using Exceptions
Threads: Doing Two or More Tasks at Once
I/O: Reading and Writing
User Interfaces That Swing
Appendix A. Common Problems and Their Solutions
Appendix B. Internet-Ready Applets
Appendix C. Collections
Appendix D. Deprecated Thread Methods
Appendix E. Reference