SEN1002 · Week 5 · GUI Components

GUI components: JFrame, JLabel, JTextField, JButton and layouts

Building a window with Swing: components, the content pane, and FlowLayout, BorderLayout, GridLayout. Code-reading and 'which layout' questions in the exam.

GUISwingJFrameJLabelJTextFieldJPasswordFieldJButtonJPanellayout managerFlowLayoutBorderLayoutGridLayoutcontent panecomponentcontainer

This week we build the parts of a graphical user interface (GUI): a window, text, a text box, a button, and the layouts that place them. Reacting to clicks (event handling) is the topic of next week. In the exam this topic usually comes as code reading: “what is visible in this window”, “which layout”, “why does this line not compile”. There is not much to memorize; it is enough to know a few defaults and how the layouts behave.

Golden rules:

  1. Everything is a String. JTextField.getText() returns a String; if you want a number, use Integer.parseInt.
  2. JPanel defaults to FlowLayout, the content pane of a JFrame to BorderLayout.
  3. In BorderLayout, one component per region. An add without a position goes to CENTER and replaces the previous one.
  4. setVisible(true) last. Use EXIT_ON_CLOSE so that the program ends when the window is closed.

TIP · Swing or JavaFX? Deitel’s book teaches with Swing (newer editions also have JavaFX chapters). This page uses Swing; it comes with the JDK. If your instructor shows JavaFX, the concepts are exactly the same: Stage ≈ JFrame, Scene ≈ content pane, Label / TextField / Button, and HBox, VBox, GridPane, BorderPane instead of layouts.

The structure of Swing

Every part of a GUI is a component. Components that hold other components are called containers. JFrame is the outermost window, and JPanel is a container you put components into and place inside the window.

ClassWhat is it for?Common methods
JFrameA window with a title that can be closedsetSize, pack, setVisible, setLayout, add, setDefaultCloseOperation
JLabelText (or an icon) that the user cannot editsetText, getText
JTextFieldSingle-line text inputgetText, setText, setEditable
JPasswordFieldPassword input shown as dotsgetPassword (returns char[])
JTextAreaMulti-line textappend, getText
JButtonA clickable buttonsetText, addActionListener (week 6)
JCheckBox, JRadioButtonSelection boxesisSelected
JPanelA container that holds a group of componentsadd, setLayout

The inheritance chain can come up in the exam as an “is-a” question:

java.awt.Component
  └─ java.awt.Container
       ├─ java.awt.Window ─ java.awt.Frame ─ javax.swing.JFrame
       └─ javax.swing.JComponent
            ├─ JLabel
            ├─ JPanel
            ├─ JTextComponent ─ JTextField ─ JPasswordField
            └─ AbstractButton ─ JButton
                              └─ JToggleButton ─ JCheckBox, JRadioButton
JButton jb = new JButton("OK");
System.out.println(jb instanceof JComponent);
System.out.println(jb instanceof Container);
System.out.println(jb instanceof Component);
Object lbl = new JLabel();
System.out.println(lbl instanceof AbstractButton);
System.out.println(new JCheckBox() instanceof AbstractButton);
true
true
true
false
true

The first window

The standard way to write a window is to create a class that derives from JFrame and set up the components in the constructor. If you keep the components as fields, the event handlers (week 6) can reach them.

import java.awt.*;
import javax.swing.*;

public class LoginFrame extends JFrame {
    private final JLabel userLabel = new JLabel("User:");
    private final JTextField userField = new JTextField(12);
    private final JLabel passLabel = new JLabel("Password:");
    private final JPasswordField passField = new JPasswordField(12);
    private final JButton loginButton = new JButton("Login");

    public LoginFrame() {
        super("Login");                         // window title
        setLayout(new FlowLayout());            // replace the default BorderLayout
        add(userLabel);
        add(userField);
        add(passLabel);
        add(passField);
        add(loginButton);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(260, 140);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new LoginFrame().setVisible(true));
    }
}

SwingUtilities.invokeLater builds the window on Swing’s own thread (the event dispatch thread); this is the correct pattern in the books. In the exam, writing new LoginFrame().setVisible(true); is also accepted.

PITFALL · the program does not end when the window closes. The default close behavior of JFrame is HIDE_ON_CLOSE: the window becomes invisible but the JVM keeps running. Do not forget to write setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE).

Reading a value from a text field

Everything the user types comes as a String. To do arithmetic you have to convert it; text that cannot be converted throws NumberFormatException.

JTextField field = new JTextField(10);
System.out.println("[" + field.getText() + "] cols=" + field.getColumns());
field.setText("Deniz Yilmaz Uzun Bir Isim");
System.out.println(field.getText().length());     // 10 columns is not a limit

JTextField num = new JTextField("12");
int n = Integer.parseInt(num.getText());
System.out.println(n * 2);
num.setText("12a");
try {
    Integer.parseInt(num.getText());
} catch (NumberFormatException e) {
    System.out.println("NumberFormatException: " + e.getMessage());
}
[] cols=10
26
24
NumberFormatException: For input string: "12a"

Layout managers

In Swing you do not position components pixel by pixel. Every container has a layout manager; it decides where the components go and what size they have. When the window grows or shrinks, it recomputes the placement.

LayoutPlacementWhere it is the defaultAdding
FlowLayoutLeft to right in order, wraps to the next row when full; each component at its own preferred sizeJPaneladd(c)
BorderLayout5 regions: NORTH, SOUTH, EAST, WEST, CENTER; CENTER fills the remaining areacontent pane of JFrameadd(c, BorderLayout.SOUTH)
GridLayoutA grid of equal-sized cells, left to right, top to bottomnoneadd(c)
JPanel panel = new JPanel();
System.out.println(panel.getLayout().getClass().getSimpleName());
JRootPane root = new JRootPane();      // the structure that builds the content pane of a JFrame
System.out.println(root.getContentPane().getLayout() instanceof BorderLayout);
FlowLayout
true

FlowLayout

The simplest. Components line up side by side in the order they are added, centered by default. new FlowLayout(FlowLayout.LEFT) aligns them to the left. If the window narrows, a component that does not fit moves to the next row. It is practical for forms, but since the arrangement changes with the window size, it is not enough for precise design.

BorderLayout

It divides the window into five regions. North and south take the full width, east and west take the remaining height, and center takes everything else. If you give no region, add(c) adds to the center.

JPanel bp = new JPanel(new BorderLayout());
JButton b1 = new JButton("One"), b2 = new JButton("Two");
bp.add(b1, BorderLayout.CENTER);
bp.add(b2, BorderLayout.CENTER);      // replaces b1
BorderLayout bl = (BorderLayout) bp.getLayout();
System.out.println(bp.getComponentCount());
System.out.println(((JButton) bl.getLayoutComponent(BorderLayout.CENTER)).getText());
2
Two

The way to put more than one component in a region is to insert a panel:

public EditorFrame() {
    super("Editor");
    add(new JLabel("Title bar text"), BorderLayout.NORTH);
    add(new JTextArea(10, 30), BorderLayout.CENTER);
    JPanel buttons = new JPanel();              // FlowLayout
    buttons.add(new JButton("Save"));
    buttons.add(new JButton("Cancel"));
    add(buttons, BorderLayout.SOUTH);           // two buttons in one region
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    pack();                                     // shrink to the preferred size
}

pack() sizes the window to the preferred size of the components; it can be used instead of setSize.

GridLayout

new GridLayout(rows, columns) or, with gaps, new GridLayout(rows, columns, hgap, vgap). All cells are of equal size and the components fill the cell completely. A 2 x 3 grid in a 300 x 100 pixel panel:

JPanel gp = new JPanel(new GridLayout(2, 3));
for (int i = 1; i <= 6; i++) gp.add(new JButton("B" + i));
gp.setSize(300, 100);
gp.doLayout();
for (Component c : gp.getComponents()) {
    Rectangle r = c.getBounds();
    System.out.println(((JButton) c).getText() + " x=" + r.x + " y=" + r.y
                       + " w=" + r.width + " h=" + r.height);
}
B1 x=0 y=0 w=100 h=50
B2 x=100 y=0 w=100 h=50
B3 x=200 y=0 w=100 h=50
B4 x=0 y=50 w=100 h=50
B5 x=100 y=50 w=100 h=50
B6 x=200 y=50 w=100 h=50

PITFALL · rows first. GridLayout(2, 3) means 2 rows and 3 columns, not the other way around. Think of it as in matrices: rows × columns.

Nested panels

Real screens do not come out of a single layout. The method: divide the screen into regions and put a JPanel with its own layout in each region. For example, a calculator: the window is a BorderLayout, with a JTextField for the result in NORTH and a keypad panel with GridLayout(4, 3, 5, 5) in CENTER.

setLayout(new GridLayout(4, 3, 5, 5));
String[] keys = {"1","2","3","4","5","6","7","8","9","*","0","#"};
for (String k : keys) add(new JButton(k));

Common mistakes

Wrong ideaThe truth
int x = field.getText();It returns a String: Integer.parseInt(field.getText())
JTextField(10) takes at most 10 charactersA width of 10 columns; not a limit
I added three buttons to the JFrame, all three are visibleDefault BorderLayout: all go to CENTER, only the last is visible
JPanel comes with BorderLayout tooJPanel defaults to FlowLayout
GridLayout(2, 3) is 2 columns 3 rows2 rows, 3 columns
The window closed, the program endedIf you did not write EXIT_ON_CLOSE, it keeps running
setVisible(true) can come firstCall it last, after adding the components
String s = pw.getPassword();It returns char[]
You do not need main to open a GUIThe program still starts from main, and you create the window there

Test yourself

Exam-style questions. Solve them on paper first, then reveal the answer.

Question 1easy

What is the default layout manager of (a) a JPanel and (b) the content pane of a JFrame?

Show answer
(a) FlowLayout, (b) BorderLayout

new JPanel() comes with FlowLayout: components go side by side, and drop to the next row when a row is full. The content pane of a JFrame comes with BorderLayout: if you do not give a position, add(c) puts it in CENTER. Mixing these two up is the source of the question "why do I only see my last button".

Question 2medium

What is printed?

JPanel bp = new JPanel(new BorderLayout());
JButton b1 = new JButton("One"), b2 = new JButton("Two");
bp.add(b1, BorderLayout.CENTER);
bp.add(b2, BorderLayout.CENTER);
BorderLayout bl = (BorderLayout) bp.getLayout();
System.out.println(bp.getComponentCount());
System.out.println(((JButton) bl.getLayoutComponent(BorderLayout.CENTER)).getText());
Show answer
2 and Two

The panel keeps both components inside (count 2). But BorderLayout has a single component in each region; adding a second one to the same region replaces the first. Only "Two" is visible on screen. If you want to put more than one thing in a region, first put them in a JPanel and add the panel to the region.

Question 3medium

A JPanel uses new GridLayout(2, 3) and buttons B1 to B6 are added in order. The panel is 300 x 100 pixels. Where is B4?

Show answer
The first cell of the second row: x=0, y=50 (100 x 50)

GridLayout(rows, columns): the number of rows comes first. The cells are of equal size: 300 / 3 = 100 wide, 100 / 2 = 50 tall. Filling goes left to right, top to bottom: B1 B2 B3 are the first row, B4 is the start of the second row.

Question 4easy

Find the compile error.

JTextField f = new JTextField("7");
int x = f.getText();
Show answer
getText() returns a String, it cannot be assigned to an int

javac: incompatible types: String cannot be converted to int. Everything that comes from a text field is a String. For a number, write int x = Integer.parseInt(f.getText());.

Question 5medium

What is printed?

JTextField num = new JTextField("12");
System.out.println(Integer.parseInt(num.getText()) * 2);
num.setText("12a");
try {
    Integer.parseInt(num.getText());
} catch (NumberFormatException e) {
    System.out.println("NumberFormatException: " + e.getMessage());
}
Show answer
24 and NumberFormatException: For input string: "12a"

"12" is converted to a number and 24 is printed. "12a" is not a number, so parseInt throws NumberFormatException; its message is For input string: "12a". In a GUI the user can type anything, so put the parse inside try/catch (week 9).

Question 6easy

JTextField field = new JTextField(10); What does 10 mean?

  1. The field holds at most 10 characters
  2. The initial text is "10"
  3. The preferred width is about 10 columns
  4. The field is 10 pixels wide
Show answer
The preferred width is about 10 columns

The constructor with an int parameter gives the number of columns: the preferred width of the box is about 10 characters. It is not a length limit; a 26-character text can be typed too (getText().length() returns 26). To give a text, use new JTextField("10").

Question 7medium

Find the compile error.

JPasswordField p = new JPasswordField();
String s = p.getPassword();
Show answer
getPassword() returns char[]

javac: incompatible types: char[] cannot be converted to String. For security, the password is given as a char array, not a String (a String stays unchanged in memory, while you can zero out an array). If needed, new String(p.getPassword()).

Question 8hard

What is printed?

JButton jb = new JButton("OK");
System.out.println(jb instanceof JComponent);
System.out.println(jb instanceof Component);
Object lbl = new JLabel();
System.out.println(lbl instanceof AbstractButton);
System.out.println(new JCheckBox() instanceof AbstractButton);
Show answer
true, true, false, true

The Swing hierarchy: Component ← Container ← JComponent ← AbstractButton ← JButton / JToggleButton ← JCheckBox. A JButton is both a JComponent and a Component. JLabel does not derive from AbstractButton: false. A JCheckBox is an AbstractButton. (If the variable had type JLabel, instanceof AbstractButton would not compile: the two types are not on the same line.)

Question 9medium

Find the problem: the window below appears empty and the program keeps running after it is closed.

public class App {
    public static void main(String[] args) {
        JFrame f = new JFrame("Demo");
        f.setVisible(true);
        f.add(new JLabel("Hello"));
        f.setSize(200, 100);
    }
}
Show answer
setVisible should come last; setDefaultCloseOperation(EXIT_ON_CLOSE) is missing

Add the components, set the size, and call setVisible(true) last; a component added to an already visible window may not appear until it is repainted. The default close behavior is HIDE_ON_CLOSE: the window is hidden but the program does not end. Add f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);. There is no compile error, both are logic errors.

Question 10easy

Which layout would you use for a calculator keypad with 4 rows of 3 equal buttons, and how do you create it with 5 pixel gaps?

Show answer
new GridLayout(4, 3, 5, 5)

Any grid that needs equal-sized cells is a GridLayout. The parameters: rows, columns, horizontal gap, vertical gap. FlowLayout wraps the buttons when the window narrows, and BorderLayout has only 5 regions.

Question 11medium

Write a class TemperatureFrame extending JFrame that shows, in a FlowLayout, a label "Celsius:", a 6-column text field, a "Convert" button and a result label "F: ?". The window title is "C to F" and closing it ends the program. (No event handling yet.)

Show answer
a JFrame subclass, setLayout + add + setDefaultCloseOperation + setSize in the constructor

Keep the components as fields so that you can reach them from a listener in week 6. Since the JFrame default is BorderLayout, set FlowLayout explicitly:

import java.awt.FlowLayout;
import javax.swing.*;

public class TemperatureFrame extends JFrame {
    private final JTextField celsiusField = new JTextField(6);
    private final JButton convertButton = new JButton("Convert");
    private final JLabel resultLabel = new JLabel("F: ?");

    public TemperatureFrame() {
        super("C to F");                 // window title
        setLayout(new FlowLayout());
        add(new JLabel("Celsius:"));
        add(celsiusField);
        add(convertButton);
        add(resultLabel);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(300, 100);
    }

    public static void main(String[] args) {
        new TemperatureFrame().setVisible(true);
    }
}

Verification: Component behaviors were run in headless mode without opening a window (java -Djava.awt.headless=true verify/SEN1002/W05.java). JFrame defaults (HIDE_ON_CLOSE, BorderLayout, CENTER replacement) were checked without making the window visible (java verify/SEN1002/W05b.java). The window examples were compiled with javac (verify/SEN1002/W05Gui.java). Compile errors: verify/SEN1002/err/E05a-c.java.

Review card

import javax.swing.*; (components) import java.awt.*; (layouts, Color, Font) Window: class F extends JFrame { F() { super("Title"); ... } } Order: add components → setSize/pack → setDefaultCloseOperation(EXIT_ON_CLOSE) → setVisible(true) LAST. Default close is HIDE_ON_CLOSE: the window goes away, the program keeps running. JLabel: shows text (setText/getText). JButton: can be clicked. JTextField(10) → width of 10 columns, NOT a limit. getText() → String → Integer.parseInt. JPasswordField.getPassword() → char[]. setEditable(false) → read-only. JPanel default FlowLayout: left to right, wraps to the next row when full, centered. JFrame content pane default BorderLayout: NORTH SOUTH EAST WEST CENTER. add(c) without position → CENTER. A second add to a region REPLACES the first. GridLayout(rows, columns, hgap, vgap): equal cells, left to right, top to bottom. Complex screen: nest panels (each panel has its own layout). Hierarchy: Component ← Container ← JComponent ← JLabel, AbstractButton ← JButton.