The Java TM Tutorial

| Start of Tutorial > Start of Trail > Start of Lesson | Search

Trail: Creating a GUI with JFC/Swing
Lesson: 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.

> `Converter` is an application that converts distance measurements between metric and U.S. units. To run it, compile the seven source files listed in the Examples Index. 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.

> Here is an annotated snapshot of `Converter`'s GUI:

> This section discusses the following features of `Converter`:

> - Swing components
> - The containment hierarchy
> - Layout management and borders
> - Separate models
> - Look and feel
> - Event Handling

### Swing Components

> As the preceding figure shows, `Converter` has the following visible components:
> - One `JFrame`
> - Two custom `JPanel`s
> - Two custom `JTextField`s
> - Two `JSlider`s
> - Two `JComboBox`es

> 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 `JPanel`s 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`:

> This diagram shows three components not labeled in the preceding snapshot because they don't paint anything noticeable on-screen:
> - One `JPanel` that serves as the content pane
> - Two custom `JPanel`s that each hold a text field and slider

> 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 `ConversionPanel`s. One of the `ConversionPanel`s 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.

> `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 `ConversionPanel`s exactly equal in size. The code sets up the `GridLayout` so that it puts the `ConversionPanel`s 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.

> 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. The `BoundedRangeModel` API documentation tells us that the interface has an implementing class named `DefaultBoundedRangeModel`. The API documentation for `DefaultBoundedRangeModel` 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?.

### 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 for more information.

| Start of Tutorial > Start of Trail > Start of Lesson | Search