Session 23: Composing GUIs

The JPanel class (Section 12.6)
Layouts (Section 12.6)
    BorderLayout
    FlowLayout
    GridLayout
Case study: Temperature conversion

The JPanel class

Textbook: Section 12.6

A JPanel object is an empty graphical component. It may seem weird that such a thing is worth talking about. But it is, for two reasons:

This last point is the reason we want to talk about panels today.

There are three JPanel methods that are particularly important.

JPanel()
Creates an empty JPanel.
void add(Component what)
Inserts what into the panel, using the default placement.
void add(Component what, Object info)
Inserts what into the panel, using info as information about where the object should be placed.

Layouts

Textbook: Section 12.6

There are several categories of GUI classes of which you should be aware:

We've covered all but the last. Now we're covering the last, composed of classes that implement the LayoutManager interface.

The layout classes tell a container class how it should lay out the components it contains. What we can do is to set the layout of a container, telling it to change its approach for handling components. Each container has such a method, called setLayout().

void setLayout(LayoutManager manager)
Changes the layout technique for the container.

Each container also has two methods for putting components into the container.
void add(Component what)
Inserts what into the panel, using the default placement.
void add(Component what, Object info)
Inserts what into the panel, using info as information about where the object should be placed.

BorderLayout

We've actually already seen the BorderLayout class: It's the default layout for a JFrame's container. Creating a BorderLayout is simple:

BorderLayout()
Creates a BorderLayout object.
When you add something to a container that's using the BorderLayout, you will generally use the add() method that takes an info parameter, and you will pass something like BorderLayout.NORTH saying on which border to place the component (or BorderLayout.CENTER to place the component in the middle).

FlowLayout

The FlowLayout class is even simpler: It places the components in left-to-right order. Each component gets sized to its preferred size. When the components fill the row, they start being placed in the next row.

FlowLayout()
Creates a FlowLayout object.
With a container using FlowLayout, you'll generally use the add() that doesn't take an info parameter.

FlowLayout is the default layout for a JPanel.

GridLayout

In the GridLayout class, components are placed left-right, top-down in a strict grid. Each component is resized to fill its grid space.

GridLayout(int rows, int columns)
Creates a GridLayout object, represent the layout strategy with rows rows and columns columns.

Case study: Temperature conversion

This example illustrates the use of the JPanel and GridLayout classes. It creates a simple temperature conversion program that looks like the following.

The way this program works is that you type a temperature into either blank, press Enter, and then the converted temperature appears in the other.

To accomplish this, I set up the JFrame container to use a one-column, two-row grid. In each row of the grid, I placed a panel. The panel uses its default FlowLayout layout and contains both a label component and a text field component.

 1  import java.awt.*;
 2  import java.awt.event.*;
 3  import javax.swing.*;
   
 4  public class TempConvert extends JFrame
 5          implements WindowListener, ActionListener {
 6      private JTextField fahr_field;
 7      private JTextField cels_field;
   
 8      public TempConvert() {
 9          super("Temperature Conversion");
10          addWindowListener(this);
   
11          fahr_field = new JTextField(8);
12          fahr_field.addActionListener(this);
   
13          cels_field = new JTextField(8);
14          cels_field.addActionListener(this);
   
15          Container contents = getContentPane();
16          contents.setLayout(new GridLayout(2, 1));
   
17          JPanel panel = new JPanel();
18          panel.add(new JLabel("Fahrenheit: "));
19          panel.add(fahr_field);
20          contents.add(panel);
   
21          panel = new JPanel();
22          panel.add(new JLabel("Celsius: "));
23          panel.add(cels_field);
24          contents.add(panel);
   
25          pack();
26      }
   
27      public void actionPerformed(ActionEvent evt) {
28          if(evt.getSource() == fahr_field) {
29              try {
30                  double temp = Double.parseDouble(fahr_field.getText());
31                  double val = (temp - 32) / 1.8;
32                  cels_field.setText("" + Math.rint(val * 100) / 100);
33              } catch(NumberFormatException e) { }
34          } else if(evt.getSource() == cels_field) {
35              try {
36                  double temp = Double.parseDouble(cels_field.getText());
37                  double val = 1.8 * temp + 32;
38                  fahr_field.setText("" + Math.rint(val * 100) / 100);
39              } catch(NumberFormatException e) { }
40          }
41      }
   
42      public void windowActivated(WindowEvent e) {}
43      public void windowClosed(WindowEvent e) {}
44      public void windowClosing(WindowEvent e) {
45          System.exit(0);
46      }
47      public void windowDeactivated(WindowEvent e) {}
48      public void windowDeiconified(WindowEvent e) {}
49      public void windowIconified(WindowEvent e) {}
50      public void windowOpened(WindowEvent e)  {}
   
51      public static void main(String[] args) {
52          (new TempConvert()).show();
53      }
54  }

Lines 9 and 11: JFrame and JTextField constructor methods

Lines 9 and 11 illustrate some new constructor methods for the JFrame and JTextField classes.

JFrame(String title)
Creates a window whose title is title.

JTextField(int width)
Creates a text field sized to show width characters. (This doesn't limit the size of the letters, as the field will scroll left and right to accomodate more. But you're only guaranteed to be able to see width characters at a time.)

Line 12: The JTextField action listener

Notice how we're defining an ActionListener for a text field in Line 12. If you add an ActionListener to a text field, its actionPerformed() method occurs whenever the user types Enter into the text field.

Lines 10 and 42-50: Window listeners

We've seen ActionListeners, an interface for defining what happens when an action is performed on an object. There are many other listeners available in Swing, however. In this program, we're defining a WindowListener, which listens for events on a window.

Unlike the ActionListener interface, which has only one method in it, the WindowListener interface includes many methods.

import java.awt.event.*;
public interface WindowListener {
    public void windowActivated(WindowEvent e);
    public void windowClosed(WindowEvent e);
    public void windowClosing(WindowEvent e);
    public void windowDeactivated(WindowEvent e);
    public void windowDeiconified(WindowEvent e);
    public void windowIconified(WindowEvent e);
    public void windowOpened(WindowEvent e);
}

In line 10, we register the TempConvert object being constructed as its own window listener. This obligates us to have the TempConvert class implement the WindowListener interface (line 5), and this obligates us to define all of the methods defined by the WindowListener interface (lines 42-50).

Actually, we ignore all of these window events except one: When the user clicks on the window's close box, the windowClosing() method of its window listeners are called. In line 45, we instruct the program to exit entirely when this occurs.

Lines 18 and 22: The JLabel class

The last new thing that this program illustrates is a use of the JLabel class, which simply represents a string that you want to appear in the window. In line 18, we use the constructor method that takes a String parameter (the string to be displayed), and we immediately add it into the window.

With most of the components we add into the window, we have had instance variables to remember them. But there's no point in trying to remember this component: After we put it into the window, we're not going to touch it again.