BUY THIS BOOK
Add to Cart

Print Book $59.99


Add to Cart

Print+PDF $77.99

Add to Cart

PDF $47.99

Safari Books Online

What is this?

Add to UK Cart

Print Book £42.50

What is this?

Looking to Reprint or License this content?


Java Swing
Java Swing, Second Edition

By Marc Loy, Robert Eckstein, Dave Wood, James Elliott, Brian Cole
Book Price: $59.99 USD
£42.50 GBP
PDF Price: $47.99

Cover | Table of Contents | Colophon


Table of Contents

Chapter 1: Introducing Swing
Welcome to Swing! By now, you're probably wondering what Swing is and how you can use it to spice up your Java applications. Or perhaps you're curious as to how the Swing components fit into the overall Java strategy. Then again, maybe you just want to see what all the hype is about. Well, you've come to the right place; this book is all about Swing and its components. So let's dive right in and answer the first question that you're probably asking right now, which is...
If you poke around the Java home page ( http://java.sun.com/ ), you'll find Swing described as a set of customizable graphical components whose look-and-feel (L&F) can be dictated at runtime. In reality, however, Swing is much more than this. Swing is the next-generation GUI toolkit that Sun Microsystems created to enable enterprise development in Java. By enterprise development , we mean that programmers can use Swing to create large-scale Java applications with a wide array of powerful components. In addition, you can easily extend or modify these components to control their appearance and behavior.
Swing is not an acronym. The name represents the collaborative choice of its designers when the project was kicked off in late 1996. Swing is actually part of a larger family of Java products known as the Java Foundation Classes ( JFC), which incorporate many of the features of Netscape's Internet Foundation Classes (IFC) as well as design aspects from IBM's Taligent division and Lighthouse Design. Swing has been in active development since the beta period of the Java Development Kit ( JDK) 1.1, circa spring of 1997. The Swing APIs entered beta in the latter half of 1997 and were initially released in March 1998. When released, the Swing 1.0 libraries contained nearly 250 classes and 80 interfaces. Growth has continued since then: at press time, Swing 1.4 contains 85 public interfaces and 451 public classes.
Although Swing was developed separately from the core Java Development Kit, it does require at least JDK 1.1.5 to run. Swing builds on the event model introduced in the 1.1 series of JDKs; you cannot use the Swing libraries with the older JDK 1.0.2. In addition, you must have a Java 1.1-enabled browser to support Swing applets. The Java 2 SDK 1.4 release includes many updated Swing classes and a few new features. Swing is fully integrated into both the developer's kit and the runtime environment of all Java 2 releases (SDK 1.2 and higher), including the Java Plug-In.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
What Is Swing?
If you poke around the Java home page ( http://java.sun.com/ ), you'll find Swing described as a set of customizable graphical components whose look-and-feel (L&F) can be dictated at runtime. In reality, however, Swing is much more than this. Swing is the next-generation GUI toolkit that Sun Microsystems created to enable enterprise development in Java. By enterprise development , we mean that programmers can use Swing to create large-scale Java applications with a wide array of powerful components. In addition, you can easily extend or modify these components to control their appearance and behavior.
Swing is not an acronym. The name represents the collaborative choice of its designers when the project was kicked off in late 1996. Swing is actually part of a larger family of Java products known as the Java Foundation Classes ( JFC), which incorporate many of the features of Netscape's Internet Foundation Classes (IFC) as well as design aspects from IBM's Taligent division and Lighthouse Design. Swing has been in active development since the beta period of the Java Development Kit ( JDK) 1.1, circa spring of 1997. The Swing APIs entered beta in the latter half of 1997 and were initially released in March 1998. When released, the Swing 1.0 libraries contained nearly 250 classes and 80 interfaces. Growth has continued since then: at press time, Swing 1.4 contains 85 public interfaces and 451 public classes.
Although Swing was developed separately from the core Java Development Kit, it does require at least JDK 1.1.5 to run. Swing builds on the event model introduced in the 1.1 series of JDKs; you cannot use the Swing libraries with the older JDK 1.0.2. In addition, you must have a Java 1.1-enabled browser to support Swing applets. The Java 2 SDK 1.4 release includes many updated Swing classes and a few new features. Swing is fully integrated into both the developer's kit and the runtime environment of all Java 2 releases (SDK 1.2 and higher), including the Java Plug-In.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Swing Features
Swing provides many features for writing large-scale applications in Java. Here is an overview of some of the more popular features.
One of the most exciting aspects of the Swing classes is the ability to dictate the L&F of each of the components, even resetting the L&F at runtime. L&Fs have become an important issue in GUI development over the past 10 years. Many users are familiar with the Motif style of user interface, which was common in Windows 3.1 and is still in wide use on Unix platforms. Microsoft created a more optimized L&F in their Windows 95/98/NT/2000 operating systems. In addition, the Macintosh computer system has its own carefully designed L&F, which most Apple users feel comfortable with.
Swing is capable of emulating several L&Fs and currently supports the Windows, Unix Motif, and "native" Java Metal L&Fs. Mac OS X comes with full support for its own L&F based on Apple's Aqua Human Interface Guidelines, although you can still access Metal if you prefer. In addition, Swing allows the user to switch L&Fs at runtime without having to close the application. This way, a user can experiment to see which L&F is best for her with instantaneous feedback. (In practice, nobody really does this, but it's still pretty cool from a geeky point of view.) And, if you're feeling really ambitious as a developer (perhaps a game developer), you can create your own L&F for each one of the Swing components!
The Metal L&F combines some of the best graphical elements in today's L&Fs and even adds a few surprises of its own. Figure 1-3 shows an example of several L&Fs that you can use with Swing, including the Metal L&F. All Swing L&Fs are built from a set of base classes called the Basic L&F. However, though we may refer to the Basic L&F from time to time, you can't use it on its own. If you're lucky enough to be developing applications in the Mac OS X environment, you'll be familiar with the L&F shown in Figure 1-4.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Swing Packages and Classes
Here is a short description of each package in the Swing libraries:
javax.accessibility
Contains classes and interfaces that can be used to allow assistive technologies to interact with Swing components. Assistive technologies cover a broad range of items, from audible text readers to screen magnification. Although the accessibility classes are technically not part of Swing, they are used extensively throughout the Swing components. We discuss the accessibility package in greater detail in Chapter 25.
javax.swing
Contains the core Swing components, including most of the model interfaces and support classes.
javax.swing.border
Contains the definitions for the abstract border class as well as eight predefined borders. Borders are not components; instead, they are special graphical elements that Swing treats as properties and places around components in place of their insets. If you wish to create your own border, you can subclass one of the existing borders in this package, or you can code a new one from scratch.
javax.swing.colorchooser
Contains support for the JColorChooser component, discussed in Chapter 12.
javax.swing.event
Defines several new listeners and events that Swing components use to communicate asynchronous information between classes. To create your own events, you can subclass various events in this package or write your own event class.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
The Model-View-Controller Architecture
Swing uses the model-view-controller architecture (MVC) as the fundamental design behind each of its components. Essentially, MVC breaks GUI components into three elements. Each of these elements plays a crucial role in how the component behaves.
Model
The model encompasses the state data for each component. There are different models for different types of components. For example, the model of a scrollbar component might contain information about the current position of its adjustable "thumb," its minimum and maximum values, and the thumb's width (relative to the range of values). A menu, on the other hand, may simply contain a list of the menu items the user can select from. This information remains the same no matter how the component is painted on the screen; model data is always independent of the component's visual representation.
View
The view refers to how you see the component on the screen. For a good example of how views can differ, look at an application window on two different GUI platforms. Almost all window frames have a title bar spanning the top of the window. However, the title bar may have a close box on the left side (like the Mac OS platform), or it may have the close box on the right side (as in the Windows platform). These are examples of different types of views for the same window object.
Controller
The controller is the portion of the user interface that dictates how the component interacts with events. Events come in many forms — e.g., a mouse click, gaining or losing focus, a keyboard event that triggers a specific menu command, or even a directive to repaint part of the screen. The controller decides how each component reacts to the event—if it reacts at all.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Working with Swing
Our introduction to Swing wouldn't be complete unless we briefly mentioned some caveats of the Swing libraries. There are two pertinent areas: multithreading and lightweight versus heavyweight components. Being aware of these issues will help you make informed decisions while working with Swing. Chapter 28 gives you in-depth guidance in these difficult areas.
Shortly before the initial release of Swing, Sun posted an article recommending that developers not use independent threads to change model states in components. Instead, once a component has been painted to the screen (or is about to be painted), updates to its model state should occur only from the event-dispatching queue. The event-dispatching queue is a system thread used to communicate events to other components. It posts GUI events, including those that repaint components.
The issue here is an artifact of the MVC architecture and deals with performance and potential race conditions. As we mentioned, a Swing component draws itself based on the state values in its model. However, if the state values change while the component is in the process of repainting, the component may repaint incorrectly—this is unacceptable. To compound matters, placing a lock on the entire model, as well as on some of the critical component data, or even cloning the data in question, could seriously hamper performance for each refresh. The only feasible solution, therefore, is to place state changes in serial with refreshes. This ensures that modifications in component state do not occur at the same time Swing is repainting any components and prevents race conditions.
One of the most frequent issues to come out of lightweight/heavyweight component use is the idea of depth, or z-order —that is, a well-defined method for how elements are stacked on the screen. Because of z-order, it is not advisable to mix lightweight and heavyweight components in Swing.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
The Swing Set Demo
If you're in a hurry to see all the components Swing has to offer, be sure to check out the Swing Set demonstration. The demonstration is extremely easy to set up. If you have the 1.3 or 1.4 SDK, the demonstration is included. If you have 1.2, you must first download and extract the demo classes and add them to your classpath. Then follow these steps:
  1. Change the directory to the demo/jfc/SwingSet2 directory. (For the 1.2 release, the directory is demo/jfc/SwingSet.)
  2. Run the SwingSet2 (or SwingSet for 1.2) jar file:
                      % java -jar SwingSet2.jar
                   
You should immediately see a splash screen indicating that the Swing Set demo is loading. When it finishes, a window appears, similar to the one in Figure 1-9.
Figure 1-9: The Swing Set demo
This demo contains a series of tabs that demonstrate almost all of the components in the Swing libraries. Be sure to check out the internal frames demo and the Metal L&F. In addition, some of the Swing creators have added "Easter eggs" throughout the Swing Set demo. See if you can find some!
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Reading This Book
We're well aware that most readers don't read the Preface. You have our permission to skip it, provided that you look at the Conventions section. That section is particularly important because in this book we experiment with a few new techniques for explaining the Swing classes. As we said earlier, everything in Swing is a JavaBean. This means that much of an object's behavior is controlled by a set of properties, which are manipulated by accessor methods. For example, the property color is accessed by the getColor( ) (to find out the color) and setColor( ) (to change the color) methods. If a property has a boolean value, the get method is often replaced by an is method; for example, the visible property would have the isVisible( ) and setVisible( ) methods.
We found the idea of properties very powerful in helping us understand Swing. Therefore, rather than listing all of a class's accessor methods, we decided to present a table for each class, listing the class's properties and showing the property's data type, which accessor methods are present, whether the property is "bound" (i.e., changing the property generates a PropertyChangeEvent), when it was introduced (1.2 is the default; 1.3 and 1.4 are marked where appropriate), and the property's default value. This approach certainly saves paper (you didn't really want a 2,000-page book, did you?) and should make it easier to understand what a component does and how it is structured. Furthermore, if you're not already in the habit of thinking in terms of the JavaBeans architecture, you should get in the habit. It's a very powerful tool for understanding component design.
The conventions we use in the property tables — plus some other conventions that we use in class diagrams — are explained in the Preface. So you may ignore the rest of the Preface as long as you familiarize yourself with the conventions we're using.
The next chapter helps AWT developers get a jump on Swing by presenting a simple application; those without AWT experience may just want to skim the chapter. In Chapter 3, we continue our discussion by presenting some of the fundamental classes of Swing and discribing how you can use the features inherent in each of these classes to shorten your overall development time. Don't stop now—the best is yet to come!
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 2: Jump-Starting a Swing Application
Now that you have an overview of Swing, let's look at a few Swing components you can put into your applications right now. This chapter shows you how to add images to buttons and how to create a rudimentary Swing application using internal frames. We won't belabor the theory and background. You'll find everything we talk about now (and tons more we don't discuss here) presented in later chapters in much greater detail. We just want to show you some of the fun stuff right away.
This chapter, and only this chapter, assumes that you have prior experience with AWT and AWT-based programs that you'd like to upgrade to use lightweight Swing components. If you are new to Java, this may not be the case; you are probably interested in learning Swing without the need to upgrade AWT applications. You can either skim this chapter or skip ahead to Chapter 3, which lays a foundation for the rest of your work in Swing.
If you want to see how easily Swing components can be dropped into existing AWT applications, though, read on.
One of the benefits of object-oriented languages is that you can upgrade pieces of a program without rewriting the rest. While practice is never as simple as theory, with Swing it's close. You can use most of the Swing components as drop-in replacements for AWT components with ease. The components sport many fancy new features worth exploiting, but they still maintain the functionality of the AWT components you're familiar with. As a general rule, you can stick a "J" in front of your favorite AWT component and put the new class to work as a Swing component. Constructors for components such as JButton, JTextField, and JList can be used with the same arguments and generate the same events as Button, TextField, and List. Some Swing containers, like JFrame, take a bit of extra work, but not much.
Graphical buttons are essential to modern user interfaces. Nice monitors and cheap hardware have made icons almost a necessity. The AWT package in Java does not directly support image buttons. You could write an extension to support them easily enough, but why bother when Swing's
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Upgrading Your AWT Programs
One of the benefits of object-oriented languages is that you can upgrade pieces of a program without rewriting the rest. While practice is never as simple as theory, with Swing it's close. You can use most of the Swing components as drop-in replacements for AWT components with ease. The components sport many fancy new features worth exploiting, but they still maintain the functionality of the AWT components you're familiar with. As a general rule, you can stick a "J" in front of your favorite AWT component and put the new class to work as a Swing component. Constructors for components such as JButton, JTextField, and JList can be used with the same arguments and generate the same events as Button, TextField, and List. Some Swing containers, like JFrame, take a bit of extra work, but not much.
Graphical buttons are essential to modern user interfaces. Nice monitors and cheap hardware have made icons almost a necessity. The AWT package in Java does not directly support image buttons. You could write an extension to support them easily enough, but why bother when Swing's JButton class provides a standard way to add image buttons?
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
A Simple AWT Application
You probably have some programs lying around that use regular AWT buttons that you'd love to replace with image buttons, but you don't have the time or, honestly, the necessity to produce your own image button class. Let's look at a simple application that demonstrates an upgrade path you can use on your own programs.
First, let's look at the code for this very simple application:
// ToolbarFrame1.java
// A simple frame containing a "toolbar" made up of several java.awt.Button
// objects. We'll be converting the Buttons to JButtons in the ToolbarFrame2.java
// file.
//
import java.awt.*;
import java.awt.event.*;

public class ToolbarFrame1 extends Frame {

  Button cutButton, copyButton, pasteButton;
  public ToolbarFrame1( ) {
    super("Toolbar Example (AWT)");
    setSize(450, 250);
    addWindowListener(new WindowAdapter( ) {
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
    });

    ActionListener printListener = new ActionListener( ) {
      public void actionPerformed(ActionEvent ae) {
        System.out.println(ae.getActionCommand( ));
      }
    };

    Panel toolbar = new Panel( );
    toolbar.setLayout(new FlowLayout(FlowLayout.LEFT));

    cutButton = new Button("Cut");
    cutButton.addActionListener(printListener);
    toolbar.add(cutButton);

    copyButton = new Button("Copy");
    copyButton.addActionListener(printListener);
    toolbar.add(copyButton);

    pasteButton = new Button("Paste");
    pasteButton.addActionListener(printListener);
    toolbar.add(pasteButton);

    // The "preferred" BorderLayout add call
    add(toolbar, BorderLayout.NORTH); 
  }

  public static void main(String args[]) {
    ToolbarFrame1 tf1 = new ToolbarFrame1( );
    tf1.setVisible(true);
  }
}
Our application has the very simple interface that is in Figure 2-1.
Figure 2-1: A simple application using three java.awt.Button objects
These buttons don't really do anything except report that they've been pressed. A standard 1.1-style handler for action events reports button presses to standard output. It's not exciting, but it lets us demonstrate that Swing buttons work the same way as AWT buttons. If you examine the code you'll notice that we had to register a window listener to tell when the user is trying to close the window, and explicitly exit the program in response. Once you update your programs to use Swing's
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Including Your First Swing Component
The first step in adding a Swing component to your application is preparing the Swing package for use. As long as you have installed SDK 1.2 or later, you don't have to take any special steps to use the Swing classes. If you're preparing an application to run with JDK 1.1, you'll need to put the swingall.jar file on the CLASSPATH so that the Swing components are available during compilation and at runtime.
In your source code, you include the Swing package by adding an import statement:
import javax.swing.*;  
Now you're ready to replace your Button objects with JButton objects. We'll also set up the application to take advantage of Swing's L&F capabilities; we've put another row of buttons at the bottom of the frame that let you select one of the standard L&Fs:
// ToolbarFrame2.java
// The Swing-ified button example  
//
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class ToolbarFrame2 extends Frame {

  // This time, let's use JButtons!
  JButton cutButton, copyButton, pasteButton;
  JButton javaButton, macButton, motifButton, winButton;

  public ToolbarFrame2( ) {
    super("Toolbar Example (Swing)");
    setSize(450, 250);

    addWindowListener(new WindowAdapter( ) {
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
    });

    ActionListener printListener = new ActionListener( ) {
      public void actionPerformed(ActionEvent ae) {
        System.out.println(ae.getActionCommand( ));
      }
    };
  
    // JPanel works similarly to Panel, so we'll use it.
    JPanel toolbar = new JPanel( );
    toolbar.setLayout(new FlowLayout(FlowLayout.LEFT));

    cutButton = new JButton("Cut");
    cutButton.addActionListener(printListener);
    toolbar.add(cutButton);

    copyButton = new JButton("Copy");
    copyButton.addActionListener(printListener);
    toolbar.add(copyButton);

    pasteButton = new JButton("Paste");
    pasteButton.addActionListener(printListener);
    toolbar.add(pasteButton);

    add(toolbar, BorderLayout.NORTH);

    // Add the L&F controls.
    JPanel lnfPanel = new JPanel( );
    LnFListener lnfListener = new LnFListener(this);
    macButton = new JButton("Mac");
    macButton.addActionListener(lnfListener);
    lnfPanel.add(macButton);
    javaButton = new JButton("Metal");
    javaButton.addActionListener(lnfListener);
    lnfPanel.add(javaButton);
    motifButton = new JButton("Motif");
    motifButton.addActionListener(lnfListener);
    lnfPanel.add(motifButton);
    winButton = new JButton("Windows");
    winButton.addActionListener(lnfListener);
    lnfPanel.add(winButton);
    add(lnfPanel, BorderLayout.SOUTH);
  }

  public static void main(String args[]) {
    ToolbarFrame2 tf2 = new ToolbarFrame2( );
    tf2.setVisible(true);
  }
}
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Beyond Buttons
Buttons are very useful, but even with great images forming the buttons, they still lack a certain glamour—every application has buttons. For the next example, let's take a look at JInternalFrame , which allows you to create free-standing frames with menus, title bars, and everything else a Frame needs right inside your application.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
What Is an Internal Frame?
Before we start coding, here's a brief rundown of the features of an internal frame:
  • Same functions as a normal Frame object, but confined to the visible area of the container it is placed in
  • Can be iconified (icon stays inside main application frame)
  • Can be maximized (frame consumes entire main application frame area)
  • Can be closed using the standard controls for application windows
  • Can be placed in a "layer," which dictates how the frame displays itself relative to other internal frames (a frame in layer 1 can never hide a frame in layer 2)
To be honest, in practice, standalone frames are often more useful than internal frames. You'll want to know about both; we have chapters dedicated to each of these topics (Chapter 8 and Chapter 9, respectively).
Figure 2-6 shows a simple internal frame using the Metal L&F.
Figure 2-6: The SimpleInternalFrame application using the Metal L&F
For this first example, we'll add an empty internal frame to an application. Once that's working, we'll expand the simple frame to create a couple of different types of internal frames and create the framework for a simple application.
One of the prerequisites for using internal frames is that you need a window capable of managing them. The Swing package provides the JDesktopPane class for this purpose. You'll see the details of the JDesktopPane in Chapter 9, but for now, here's how to get one started:
// Set up the layered pane.
JDesktopPane desktop = new JDesktopPane( );
add(desktop, BorderLayout.CENTER);
With the desktop in place, you can create a new internal frame and show it. The JInternalFrame constructor takes five arguments that tailor the look and functionality of the frame:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
A Bigger Application
Now that you've seen how to create internal frames and played around with them a bit, let's tackle a slightly larger problem. We want to build an application that can pop up internal frames that you can actually use. This starter application is a web site manager that shows us a list of HTML pages at a site and, for any of those pages, allows us to pop up the page in a separate frame and edit it. We'll keep the main list of HTML pages in one "site" frame that contains a simple list box.
Once you have a site built up with a couple of pages, you can click on any entry in the list, and if the file exists, we'll create a new "page" frame and load the file into a JTextArea object for you to edit. You can modify the text and save the file using the File menu in the page frame.
As a bonus, we'll put those cut, copy, and paste icons to use as well. You can manipulate text in any of the open page frames. The icons work as Action objects by looking at the selected text and insertion point of the active frame. (We alluded to the Action class after our last Toolbar example. We'll demonstrate it here and discuss it thoroughly at the start of the next chapter.) If the active frame is a site frame, nothing happens.
You could certainly add a lot of features to this application and make it a real working program, but we don't want to get mired down in details just yet. (If you want to get really fancy, you could look at some of the editor kits discussed in Chapter 23 and build yourself a real HTML editor.) Figure 2-9 shows the finished application with a couple of open frames.
Figure 2-9: The SiteManager application running on a platform where Metal is the default L&F
We break the code for this application into three separate classes to make discussing it more manageable. The first class handles the real application frame. The constructor handles all of the interface setup work. It sets up the toolbar, as well as the Cut, Copy, and Paste buttons. It uses the default L&F for the platform on which it is run. (You could certainly attach the
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 3: Swing Component Basics
The previous chapter showed how easy it is to create some impressive programs with Swing components. Now it's time to dig in a little deeper. We begin this chapter by presenting an overview of a few key (but lower-level) helper classes such as Action, GraphicsContext, ChangeEvent, and PropertyChangeEvent, as well as the HeadlessException exception. We spend the remainder of the chapter introducing the JComponent class, the heart and soul of all Swing components.
Actions are a popular addition to Swing. An action allows a programmer to bundle a commonly used procedure and its bound properties (such as its name and an image to represent it) into a single class. This construct comes in handy if an application needs to call upon a particular function from multiple sources. For example, let's say that a Swing programmer creates an action that saves data to disk. The application could then invoke this action from both the Save menu item on the File menu and the Save button on a toolbar. Both components reference the same action object, which saves the data. If the Save function is disabled for some reason, this property can be set in the action as well. The menu and toolbar objects are automatically notified that they can no longer save any data, and they can relay that information to the user.
Swing containers, such as JMenu, JPopupMenu, and JToolBar, can each accept action objects with their add( ) methods. When an action is added, these containers automatically create a GUI component, which the add( ) method then returns to you for customization. For example, a JMenu or a JPopupMenu creates and returns a JMenuItem from an Action while a JToolBar creates and returns a JButton. The action is then paired with the newly created GUI component in two ways: the GUI component registers as a PropertyChangeListener for any property changes that might occur in the action object, while the action object registers as an
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Understanding Actions
Actions are a popular addition to Swing. An action allows a programmer to bundle a commonly used procedure and its bound properties (such as its name and an image to represent it) into a single class. This construct comes in handy if an application needs to call upon a particular function from multiple sources. For example, let's say that a Swing programmer creates an action that saves data to disk. The application could then invoke this action from both the Save menu item on the File menu and the Save button on a toolbar. Both components reference the same action object, which saves the data. If the Save function is disabled for some reason, this property can be set in the action as well. The menu and toolbar objects are automatically notified that they can no longer save any data, and they can relay that information to the user.
Swing containers, such as JMenu, JPopupMenu, and JToolBar, can each accept action objects with their add( ) methods. When an action is added, these containers automatically create a GUI component, which the add( ) method then returns to you for customization. For example, a JMenu or a JPopupMenu creates and returns a JMenuItem from an Action while a JToolBar creates and returns a JButton. The action is then paired with the newly created GUI component in two ways: the GUI component registers as a PropertyChangeListener for any property changes that might occur in the action object, while the action object registers as an ActionListener on the GUI component. Figure 3-1 shows the interactions between a menu item or toolbar and an Action.
Figure 3-1: An action in conjunction with a Swing item and toolbar
Essentially, this means that if the menu item or button is selected by the user, the functionality inside the action is invoked. On the other hand, if the action is disabled, it sends a
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Graphical Interface Events
Whenever you interact with your application's user interface, the application receives an event from the windowing system to let it know that something happened. Some events come from the mouse, such as mouse clicks, mouse movements, and mouse drags. Other events come from the keyboard, such as key presses and key releases. Every component generates events. Different components generate different events as dictated by their purpose (and their L&F). For example, pressing a JButton generates an ActionEvent (which is really just a converted mouse event). The ActionEvent class bundles up interesting stuff like which button the event came from, when the button was pressed, whether any modifier keys (such as Shift or Ctrl) were pressed at the time of the event, and so on.
While the event-dispatching and -handling mechanism is grounded in the world of AWT (and beyond the scope of this book), we do want you to know what events the various Swing components generate—and when. The what of the events is discussed in conjunction with each of the components. As we introduce components like JTextField, JButton, and JTable, we show the events that they fire and the methods you use to attach listeners and catch the events.
The when of the events is a bit more difficult to describe. Rather than attempt to list every possible scenario for every component, we've built a small utility: EEL, the Every Event Listener. The EEL class implements every listener interface from the java.awt.event and javax.swing.event packages. It has a variety of logging mechanisms to show you the events coming from your components. You attach an EEL instance to a component (or to multiple components) using the component's add . . . Listener( ) method(s). You can choose to have the events sent to a file, to your console, or to an onscreen text area.
This discussion really is beyond the scope of the book. So we're posting this utility and its documentation on the web site for this book (http://www.oreilly.com/catalog/jswing2
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Graphics Environments
SDK 1.4 recognizes a great deal of information about its environment. You can retrieve that information for your own code through the GraphicsEnvironment , GraphicsDevice , and GraphicsConfiguration classes from the java.awt package. While they aren't part of Swing proper, these classes are definitely useful for Swing applications, especially those that take full advantage of their environment.
To sum up these classes, a system keeps a local GraphicsEnvironment object that describes the devices on the system with an array of GraphicsDevice objects. Each GraphicsDevice contains (or at least may contain) multiple configurations of device capabilities (such as pixel formats or which visual screen you're on) bundled up in an array of GraphicsConfiguration objects.
The GraphicsConfiguration class should not be confused with the DisplayMode class (although it's easy to do so). The display mode is something with which most savvy computer users will be familiar. On a system that supports multisync monitors, the DisplayMode class encapsulates the width, height, color-depth, and refresh rate information for a given mode. The GraphicsConfiguration class stores things like square versus rectangular pixels. GraphicsConfiguration could even be used for devices such as printers. The configuration information is highly dependent on the native platform and thus varies widely from system to system. In any given system, both configurations and modes can be found through the available GraphicsDevice objects.
If you're curious about the various graphics configurations on your system, try out this little program, GuiScreens.java. It prints information on all devices and configurations. For each configuration, it also pops up a JFrame using that configuration.
// GuiScreens.java
//
import java.awt.*;
import javax.swing.*;

public class GuiScreens {
  public static void main(String[] args) {
    Rectangle virtualBounds = new Rectangle( );
    GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment( );
    GraphicsDevice[] gs = ge.getScreenDevices( );
    JFrame frame[][] = new JFrame[gs.length][];
    for (int j = 0; j < gs.length; j++) { 
      GraphicsDevice gd = gs[j];
      System.out.println("Device " + j + ": " + gd);
      GraphicsConfiguration[] gc = gd.getConfigurations( );
      frame[j] = new JFrame[gc.length];

      for (int i=0; i < gc.length; i++) {
        System.out.println("  Configuration " + i + ": " + gc[i]);
        System.out.println("    Bounds: " + gc[i].getBounds( ));
        virtualBounds = virtualBounds.union(gc[i].getBounds( ));
        frame[j][i] = new JFrame("Config: " + i, gc[i]);
        frame[j][i].setBounds(50, 50, 400, 100);
        frame[j][i].setLocation(
          (int)gc[i].getBounds( ).getX( ) + 50,
          (int)gc[i].getBounds( ).getY( ) + 50);
        frame[j][i].getContentPane( ).add(new JTextArea("Config:\n" + gc[i]));
	frame[j][i].setDefaultCloseOperation( WindowConstants.EXIT_ON_CLOSE );
        frame[j][i].setVisible(true);
      }
      System.out.println("Overall bounds: " + virtualBounds);
    }
  }
}
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Sending Change Events in Swing
Swing uses two different change event classes. The first is the standard java.beans.PropertyChangeEvent class. This class passes a reference to the object, sending the change notification as well as the property name, its old value, and its new value. The second, javax. swing.event.ChangeEvent , is a lighter version that passes only a reference to the sending object—in other words, the name of the property that changed, as well as the old and new values, are omitted.
Since the ChangeEvent class is not part of the JavaBeans specifications, properties that use this event are not "bound" according to the JavaBeans standard. In order to prevent confusion, properties that use a ChangeEvent to notify listeners of property changes have not been marked as bound in our property tables.
Because the ChangeEvent includes only a reference to the event originator, which never changes, you can always define a single ChangeEvent and reuse it over and over when firing events from your component.
The ChangeEvent is a stripped-down version of the java.beans.PropertyChangeEvent class. This class has no methods or properties, only a constructor. This simplicity makes it a popular class for developers wanting to fire off their own events. Recipients get a reference to the source of the event but then must query the source directly to find out what just happened. It's great for quick notifications or instances in which the state of the source component is so complex it's hard to predict which pieces of information the recipient will need, but it shouldn't be used simply to save the component author a little time at the expense of runtime inefficiency if the recipient always needs to look up information that could have been part of a PropertyChangeEvent.

Section 3.4.1.1: Constructor

public ChangeEvent(Object source)
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
The JComponent Class
JComponent is an abstract class that almost all Swing components extend; it provides much of the underlying functionality common throughout the Swing component library. Just as the java.awt.Component class serves as the guiding framework for most of the AWT components, the javax.swing.JComponent class serves an identical role for the Swing components. We should note that the JComponent class extends java.awt.Container (which in turn extends java.awt.Component), so it is accurate to say that Swing components carry with them a great deal of AWT functionality as well.
Because JComponent extends Container, many Swing components can serve as containers for other AWT and Swing components. These components may be added using the traditional add( ) method of Container. In addition, they can be positioned with any Java layout manager while inside the container. The terminology remains the same as well: components that are added to a container are said to be its children; the container is the parent of those components. Following the analogy, any component that is higher in the tree is said to be its ancestor , while any component that is lower is said to be its descendant.
Recall that Swing components are considered "lightweight." In other words, they do not rely on corresponding peer objects within the operating system to render themselves. As we mentioned in Chapter 1, lightweight components draw themselves using the standard features of the abstract Graphics object, which not only decreases the amount of memory each component uses but allows components to have transparent portions and take on nonrectangular shapes. And, of course, lightweight components are free of a dedicated L&F.
It's not out of the question to say that a potential benefit of using lightweight components is a decrease in testing time. This is because the functionality necessary to implement lightweight components in the Java virtual machine is significantly less than that of heavyweight components. Heavyweight components must be individually mapped to their own native peers. On the other hand, one needs to implement only a single lightweight peer on each operating system for all the Swing components to work correctly. Hence, there is a far greater chance that lightweight components will execute as expected on any operating system and not require rounds of testing for each platform.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Responding to Keyboard Input
Swing provides a flexible framework for keyboard-based control, which can be used by any component. The rest of the chapter explains this mechanism.
InputMap maps keystrokes to logical action names. When the user types a key combination, it's looked up in the input map of the focused component (and perhaps other components in the active window, as described earlier). If a match is found, the resulting object is used as a key in the corresponding component's ActionMap to look up the concrete Action class to be invoked. The platform-specific L&F implementations provide InputMaps consistent with the key-binding conventions for their platforms.
When looking for values in an InputMap, a java.awt.KeyStroke is always used as the key. KeyStroke is a simple, immutable class that represents a particular keyboard action (including any modifier keys). KeyStrokes are intended to be unique (that is, if two KeyStroke variables represent the same action, they should reference the same KeyStroke instance). To ensure uniqueness, you can't create KeyStrokes directly; you must obtain them through the static getKeyStroke( ) factory methods in the KeyStroke class.
Although the result of looking up a KeyStroke in an InputMap is an arbitrary object, and any object can be used as a key for looking up an action in an ActionMap, in practice the values are Strings. By convention, their content is a descriptive name for the action to be performed (such as copy, print, save, or the like). This allows InputMaps to be largely self-documenting (it's easy to print their contents as a "cheat sheet" showing the keys that invoke particular commands) and also improves the readability of code that requests actions programmatically. The most common way this string is obtained is by calling getName( ) on the Action to be added to the map.
InputMaps can be chained together so that common functionality can be shared in a basic InputMap; specialized components can add custom keystrokes to their own
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 4: Labels and Icons
We'll begin our look at the Swing components with the JLabel class. In addition, we'll look at Swing's Icon interface and an implementation of this interface called ImageIcon. With just these few constructs, you'll begin to see how Swing aids in the sophisticated UI development in Java.
Swing allows you to create labels that can contain text, images, or both. We'll begin this chapter with a look at the JLabel class.
The JLabel class allows you to add basic, noninteractive labels to a user interface. Because of its inherent simplicity, there is no model class for JLabel. Figure 4-1 shows a class diagram for JLabel. We'll get into the two relationships to Icon a little later.
Figure 4-1: JLabel class diagram
JLabel objects may consist of both text and graphics (icons), but for simple text-only labels, the interface with JLabel is very similar to that of java.awt.Label. The code to create and display a very simple text label looks like this:
// SimpleJLabelExample.java
//
import javax.swing.*;

public class SimpleJLabelExample {
  public static void main(String[] args) {
    JLabel label = new JLabel("A Very Simple Text Label");

    JFrame frame = new JFrame( );
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane( ).add(label); // Adds to CENTER
    frame.pack( );
    frame.setVisible(true);
  }
}
Running this simple program produces the display shown in Figure 4-2.
Figure 4-2: A simple JLabel
The JLabel class contains the properties shown in Table 4-1. The icon and disabledIcon properties specify the icon to be displayed by default and when the label is disabled, respectively. If an
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Labels
Swing allows you to create labels that can contain text, images, or both. We'll begin this chapter with a look at the JLabel class.
The JLabel class allows you to add basic, noninteractive labels to a user interface. Because of its inherent simplicity, there is no model class for JLabel. Figure 4-1 shows a class diagram for JLabel. We'll get into the two relationships to Icon a little later.