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.
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:
- Everything is a String.
JTextField.getText()returns a String; if you want a number, useInteger.parseInt. - JPanel defaults to FlowLayout, the content pane of a JFrame to BorderLayout.
- In BorderLayout, one component per region. An
addwithout a position goes to CENTER and replaces the previous one. setVisible(true)last. UseEXIT_ON_CLOSEso 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, andHBox,VBox,GridPane,BorderPaneinstead 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.
| Class | What is it for? | Common methods |
|---|---|---|
JFrame | A window with a title that can be closed | setSize, pack, setVisible, setLayout, add, setDefaultCloseOperation |
JLabel | Text (or an icon) that the user cannot edit | setText, getText |
JTextField | Single-line text input | getText, setText, setEditable |
JPasswordField | Password input shown as dots | getPassword (returns char[]) |
JTextArea | Multi-line text | append, getText |
JButton | A clickable button | setText, addActionListener (week 6) |
JCheckBox, JRadioButton | Selection boxes | isSelected |
JPanel | A container that holds a group of components | add, 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 writesetDefaultCloseOperation(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.
| Layout | Placement | Where it is the default | Adding |
|---|---|---|---|
FlowLayout | Left to right in order, wraps to the next row when full; each component at its own preferred size | JPanel | add(c) |
BorderLayout | 5 regions: NORTH, SOUTH, EAST, WEST, CENTER; CENTER fills the remaining area | content pane of JFrame | add(c, BorderLayout.SOUTH) |
GridLayout | A grid of equal-sized cells, left to right, top to bottom | none | add(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 idea | The truth |
|---|---|
int x = field.getText(); | It returns a String: Integer.parseInt(field.getText()) |
JTextField(10) takes at most 10 characters | A width of 10 columns; not a limit |
| I added three buttons to the JFrame, all three are visible | Default BorderLayout: all go to CENTER, only the last is visible |
| JPanel comes with BorderLayout too | JPanel defaults to FlowLayout |
GridLayout(2, 3) is 2 columns 3 rows | 2 rows, 3 columns |
| The window closed, the program ended | If you did not write EXIT_ON_CLOSE, it keeps running |
setVisible(true) can come first | Call it last, after adding the components |
String s = pw.getPassword(); | It returns char[] |
You do not need main to open a GUI | The 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.
What is the default layout manager of (a) a JPanel and (b) the content pane of a JFrame?
Show answer
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".
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
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.
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
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.
Find the compile error.
JTextField f = new JTextField("7");
int x = f.getText();Show answer
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());.
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
"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).
JTextField field = new JTextField(10); What does 10 mean?
- The field holds at most 10 characters
- The initial text is "10"
- The preferred width is about 10 columns
- The field is 10 pixels wide
Show answer
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").
Find the compile error.
JPasswordField p = new JPasswordField();
String s = p.getPassword();Show answer
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()).
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
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.)
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
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.
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
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.
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
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.