Skip to content

TD4 — Swing: Car Control Panel

← Part 2 Overview

S7 Inf A3 — Java for Graphical and Mobile Programming
Stéphane Derrode — Centrale Lyon
Part 2 — GUI with Swing
Duration: 2h · Continue the td1 Maven project (or create td4)


Objectives

  • Build a complete Swing window with JFrame and nested JPanels
  • Use BorderLayout, FlowLayout, and GridLayout
  • Connect ActionListener events to the Car model from Part 1
  • Read and write component values (JTextField, JLabel, JComboBox)
  • Use JMenuBar and JOptionPane

Part 1 — Project Setup (5 min)

Reuse your td1 project which already contains Car.java.
Verify the three imports compile correctly in a new file:

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

If you need a fresh Maven project, create td4 with the same pom.xml as TD1 and copy Car.java into it.


Part 2 — CarUI — Basic Window (35 min)

2.1 Specification

Create src/main/java/com/s7infa3/CarUI.java.

The window must look like this:

┌─────────────────────────────────────┐
│  Car Control                        │  ← JFrame title
├─────────────────────────────────────┤
│  Car[Clio, 90hp, off, 0 km/h]       │  ← NORTH: status JLabel
├─────────────────────────────────────┤
│  Model: [ Clio ]  Power: [ 90 ]     │  ← CENTER: JPanel (GridLayout)
│  Accel: [  50 ]   Turbo: [ ]        │
├─────────────────────────────────────┤
│ [Start][Stop][Accelerate][Brake]    │  ← SOUTH: JPanel (FlowLayout)
│            [New Car]                 │
└─────────────────────────────────────┘

2.2 Component inventory

Component Variable name Initial state
JLabel status display statusLabel car.toString()
JTextField model entry modelField "Clio" (8 cols)
JTextField power entry powerField "90" (5 cols)
JTextField accel entry accelField "50" (5 cols)
JCheckBox turbo mode turboCheck unchecked
JButton Start startBtn enabled
JButton Stop stopBtn enabled
JButton Accelerate accelBtn enabled
JButton Brake brakeBtn enabled
JButton New Car newBtn enabled

2.3 Behaviour

Button Action
Start Call car.start(), call refresh()
Stop Call car.stop(), call refresh()
Accelerate Parse accelFieldv; if Turbo is checked, v *= 2; call car.accelerate(v), call refresh(). If parse fails, show JOptionPane.showMessageDialog with an error
Brake Parse accelFieldv; call car.brake(v), call refresh()
New Car Parse powerField, create new Car(modelField.getText(), p), call refresh(). If parse fails, show error dialog

refresh() must update statusLabel with car.toString().

2.4 Skeleton

package com.s7infa3;

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

public class CarUI extends JFrame {

    private Car car = new Car("Clio", 90);
    private JLabel  statusLabel;
    private JTextField modelField, powerField, accelField;
    private JCheckBox  turboCheck;

    public CarUI() {
        setTitle("Car Control");
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLayout(new BorderLayout(8, 8));

        buildNorth();   // TODO: status label
        buildCenter();  // TODO: input fields
        buildSouth();   // TODO: buttons

        pack();
        setLocationRelativeTo(null); // center on screen
    }

    private void buildNorth() {
        // TODO: create statusLabel with car.toString()
        // setBorder(BorderFactory.createEmptyBorder(8,8,8,8))
        // add(statusLabel, BorderLayout.NORTH)
    }

    private void buildCenter() {
        // TODO: GridLayout(2, 4, 8, 4) panel
        // "Model:" + modelField, "Power:" + powerField
        // "Accel:" + accelField, "Turbo:" + turboCheck
    }

    private void buildSouth() {
        // TODO: FlowLayout panel, all 5 buttons
        // Wire each button's ActionListener
    }

    private void refresh() {
        // TODO: update statusLabel text with car.toString()
    }

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

2.5 Expected output

After clicking Start then Accelerate (value 50):

Car[Clio, 90hp, on, 50 km/h]

After clicking Brake (value 20):

Car[Clio, 90hp, on, 30 km/h]

After clicking Stop:

Car[Clio, 90hp, off, 0 km/h]

After entering model Polo, power 110 and clicking New Car:

Car[Polo, 110hp, off, 0 km/h]


Part 3 — Add a Menu (20 min)

Add a JMenuBar to your CarUI:

┌─────────────┬──────────────┐
│ File        │ Help         │
├─────────────┤              │
│ Save state  │ About        │
│ ─────────── │              │
│ Exit        │              │
└─────────────┘
Menu item Behaviour
Save state Print car.toString() to the console (file I/O from CM2 is optional)
Exit System.exit(0)
About Show JOptionPane.showMessageDialog with the text "Car Control v1.0\nStéphane Derrode — Centrale Lyon"
private void buildMenu() {
    JMenuBar menuBar = new JMenuBar();

    JMenu fileMenu = new JMenu("File");
    // TODO: add Save state and Exit items

    JMenu helpMenu = new JMenu("Help");
    // TODO: add About item

    menuBar.add(fileMenu);
    menuBar.add(helpMenu);
    setJMenuBar(menuBar);
}

Call buildMenu() from the constructor before pack().


Part 4 — CarSelector — JComboBox (20 min)

Add a fleet selector to the window. The user can choose a pre-configured Car from a drop-down and the display updates instantly.

4.1 Pre-configured fleet

private Car[] fleet = {
    new Car("Clio", 90),
    new Car("Polo", 110),
    new Car("Ferrari", 280),
};
private String[] names = {"Clio (90hp)", "Polo (110hp)", "Ferrari (280hp)"};

4.2 Add to CENTER panel

JComboBox<String> selector = new JComboBox<>(names);
selector.addActionListener(e -> {
    car = fleet[selector.getSelectedIndex()];
    refresh();
});

When the user selects an entry, the current car field is updated and the status label refreshes.


Part 5 — Exploration (remaining time)

5.1 Make the Accelerate button disabled (setEnabled(false)) when car.isStarted() is false, and re-enable it after Start. Use refresh() to keep the button state in sync.

5.2 Add a JSlider (range 0–200, initial value 50) that sets the acceleration value. When the slider moves, update accelField to show the current value.

5.3 Change the statusLabel text color to Color.GREEN when the car is started and Color.RED when stopped.


Deliverable

No formal submission. Verify all button behaviours before leaving.


Common Errors

Error Cause Fix
NumberFormatException Non-numeric text in powerField Wrap Integer.parseInt() in try/catch
Window is blank setVisible(true) called before components added Move setVisible after pack()
Buttons have no effect Listener not registered Check addActionListener is called
pack() gives tiny window No components have preferred sizes Add content before calling pack()
Menu not showing setJMenuBar() not called Call it on the JFrame, not on a JPanel
Accelerate seems stuck Car not started, or already at maxSpeed() Click Start first; remember the speed is capped at 80 + power