Previous | Next | Trail Map | Creating a GUI with JFC/Swing | Swing Features and Concepts

The Anatomy of a Swing-Based Program

This section picks apart a Swing program, called Converter, that has a GUI. You can see how this program is implemented by looking at its source code, which is mainly in Converter.java and ConversionPanel.java. However, this section doesn't talk about individual lines of code. Instead, it concentrates on how the Converter program uses the GUI features provided by the Java platform. If you get lost while looking at the Converter source code, you might want to refresh your memory by going to A Quick Tour of a Swing Application's Code(in the Creating a User Interface trail).

Converter is an application that converts distance measurements between metric and U.S. units. To run it, compile the following seven source files: Converter.java, ConversionPanel.java, ConverterRangeModel.java, FollowerRangeModel.java, DecimalField.java, FormattedDocument.java, and Unit.java. Once you've compiled the program, run it by invoking the interpreter on the Converter class. If you need help compiling or running Converter, see Compiling and Running a Swing Program(in the Creating a User Interface trail).

Here is an annotated snapshot of Converter's GUI:

Converter
[PENDING: point to visible components: "JFrame", "JPanel (ConversionPanel)" (x2 pointing to the panels that say "Metric System" and "U.S. System"), "JTextField (DecimalField)" (x2), JSlider (x2), JComboBox (x2)]

This section discusses the following features of Converter:

Swing Components

As the preceding figure shows, Converter has the following visible components:

The JFrame is the top-level container; it provides the only window in the application. All the other components in the application are contained by the JFrame.

Except for the top-level container, all the visible components in Converter inherit from JComponent. The JComponent class provides many features, such as support for borders and accessibility. The two custom JPanels shown in the snapshot use the border support to provide titles (for example, "Metric System") and to paint boxes around themselves.

The Containment Hierarchy

The following figure shows the containment hierarchy for the JFrame:

                        JFrame
                          |
                         ...
                          |
                       JPanel (custom content pane)
                          |
             +---------------------------------+
             |                                 |
          JPanel                            JPanel
     (ConversionPanel)                 (ConversionPanel)
             |                                 | (copy left half here)
         +---------+
         |         |
      JPanel  JComboBox
     (custom)
         |                      
     +----------+
     |          |
JTextField   JSlider
(DecimalField)

This diagram shows three components not labeled in the preceding snapshot because they don't paint anything noticeable on-screen:

These three components exist to affect layout. They do this either by simplifying layout or by adding "empty" borders that add space to the layout. Grouping components -- whether in visible or invisible containers -- also provides hints to assistive technologies. For example, grouping a text field and slider in their own container gives assistive technologies the information that the text field and slider might be closely related.

Under the content pane are two ConversionPanels. One of the ConversionPanels holds the components related to metric distances; the other one does the same for U.S. distances.

Each ConversionPanel contains three visible components: a text field, a slider, and a combo box. The text field and slider are grouped together in a JPanel, mainly to make layout simpler.

Layout Management and Borders

The following figure shows a colorized version of Converter. In this version, each container has a background color, so that you can easily see the parts of the containers that aren't covered by other components. Note that all the containers are opaque; otherwise, the background color would not automatically be painted on the container.
Colorful Converter
[PENDING: add labels.
red area: "JPanel (custom content pane); uses GridLayout"
each cyan area: "JPanel (ConversionPanel); uses BoxLayout"
each dark blue area: "JPanel (container of text field and slider); uses BoxLayout" ]

Converter creates five layout manager objects -- one instance of GridLayout and four of BoxLayout.

The first JPanel (the custom content pane) uses GridLayout to make the ConversionPanels exactly equal in size. The code sets up the GridLayout so that it puts the ConversionPanels in a single column (two rows), with five pixels between components. The JPanel is initialized to have an empty border that adds five pixels between the panel and the sides of the frame.

Each ConversionPanel has a compound border. On the outside is a titled border, and on the inside is an empty border. The titled border paints a look-and-feel-specific box around the ConversionPanel and places the panel's title in the box. The empty border puts some more space between the ConversionPanel and its contents.

Each ConversionPanel uses a BoxLayout manager to place its contents, a JPanel and a JComboBox, in a row. By setting the Y alignment of both the panel and combo box, the program aligns the top of the panel with the top of the combo box.

The JPanel that groups the text field and slider is implemented with an unnamed subclass of JPanel. This subclass overrides the getMinimumSize, getPreferredSize, and getMaximumSize methods so that they all return the same value: 150 pixels wide and the preferred height. This is how we ensure that both text-slider groups have the same width, even though they're controlled by different layout managers. We need to create a subclass of JPanel, instead of just calling the setXxxxSize methods, because the preferred height of components is determined at run time, by the layout manager.

The JPanel that groups the text field and slider uses a top-to-bottom BoxLayout manager so that the text field is placed on top of the slider. This panel also has an empty border that adds a bit of space to its right, between it and the combo box.

Separate Models

This program uses three custom models. The first is a data model for the text fields. Text data models are known as document models. The document model parses the value that the user enters into the text field. It also formats the number so that it looks nice. We borrowed this document model, without changing it, from the example presented in Creating a Validated Text Field(in the Creating a User Interface trail).

The other two custom models are slider data models. They ensure that the data displayed by the application is kept in only one place -- in the model for the top slider. The top slider's model is an instance of a custom class called ConverterRangeModel. The bottom slider uses a second custom class, FollowerRangeModel, which forwards all requests to get and set data to the top slider's model.

All slider data models must implement the BoundedRangeModel interface. We learned this by looking at the API section of How to Use Sliders(in the Creating a User Interface trail). The BoundedRangeModel API documentation(in the API reference documentation) tells us that the interface has an implementing class named DefaultBoundedRangeModel. The API documentation for DefaultBoundedRangeModel(in the API reference documentation) shows that it's a general-purpose implementation of BoundedRangeModel.

We didn't use DefaultBoundedRangeModel directly because it stores data as integers, and we need to store floating-point data. Thus, we implemented ConverterRangeModel as a subclass of Object, checking it against the DefaultBoundedRangeModel source code (distributed with the JFC 1.1 and JDK 1.2 releases), to make sure we implemented the model correctly. We then implemented FollowerRangeModel as a subclass of ConverterRangeModel.

Look and Feel

The Converter program sets itself up to use the Java Look & Feel. By changing the value of its LOOKANDFEEL variable, you can make it use a different look and feel. Three of its incarnations are pictured in What Are the JFC and Swing?(in the Creating a User Interface trail).

Event Handling

The Converter program creates several event handlers:
Action listeners
Each combo box has an action listener. Whenever the user selects a new unit of measure, the action listener notifies the relevant slider's model and resets the maximum values of both sliders.

Each text field has an action listener that's notified when the user presses Return to indicate that typing has ended. This action listener updates the corresponding slider's model to reflect the text field's value.

Change listeners
Each slider model has a custom change listener. Whenever a slider's value changes, the custom change listener updates the appropriate text field. We didn't have to register the sliders as listeners on their own models, since Swing automatically does so. In other words, whenever a program sets a value in a slider's model, that slider is automatically updated to reflect the model's new state.

The model for the bottom slider adds a change listener to the top slider's model. This change listener fires a change event to the bottom slider model's change listeners, which are the bottom slider and the custom change listener described in the previous paragraph. The effect is that when the top slider's value changes, the value displayed in the bottom slider and text field is updated. It isn't necessary to notify the top slider of changes in the bottom slider, since the bottom slider's model forwards all data-setting requests to the top slider's model.

Window listener
A window listener on the frame causes the application to exit when the window is closed.
Most of the Converter program's listeners are implemented in anonymous inner classes. Although inner classes might seem hard to read, at first, they actually make code easier to understand, once you're used to them. By keeping an event handler implementation close to where the event handler is registered, inner classes help you, and those who follow you, to easily find the entire implementation of the event handler. See Using Adapters and Inner Classes to Handle Events(in the Creating a User Interface trail) for more information.


Previous | Next | Trail Map | Creating a GUI with JFC/Swing | Swing Features and Concepts