Skip to content

TD4 — Swing: Voiture 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 Voiture 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 Voiture.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 Voiture.java into it.


Part 2 — VoitureUI — Basic Window (30 min)

2.1 Specification

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

The window must look like this:

┌─────────────────────────────────┐
│  Voiture Control                │  ← JFrame title
├─────────────────────────────────┤
│  Voiture[p=4, demarree=false,   │  ← NORTH: status JLabel
│  v=0.0]                         │
├─────────────────────────────────┤
│  Power: [  4  ]  Turbo: [ ]     │  ← CENTER: JPanel (GridLayout)
│  Speed:  [  0  ]                │
├─────────────────────────────────┤
│  [Start] [Stop] [Accelerate]    │  ← SOUTH: JPanel (FlowLayout)
│          [New Voiture]          │
└─────────────────────────────────┘

2.2 Component inventory

Component Variable name Initial state
JLabel status display statusLabel voiture.toString()
JTextField power entry powerField "4" (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 New Voiture newBtn enabled

2.3 Behaviour

Button Action
Start Call voiture.demarre(), call refresh()
Stop Call voiture.arrete(), call refresh()
Accelerate Parse accelField, call voiture.accelere(v), call refresh(). If parse fails, show JOptionPane.showMessageDialog with an error message
New Voiture Parse powerField, create new Voiture(p), call refresh(). If parse fails, show error dialog
Turbo checkbox When checked, multiply acceleration by 2 in the Accelerate handler

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

2.4 Skeleton

package com.s7infa3;

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

public class VoitureUI extends JFrame {

    private Voiture voiture = new Voiture(4);
    private JLabel  statusLabel;
    private JTextField powerField, accelField;
    private JCheckBox  turboCheck;

    public VoitureUI() {
        setTitle("Voiture 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 voiture.toString()
        // setBorder(BorderFactory.createEmptyBorder(8,8,8,8))
        // add(statusLabel, BorderLayout.NORTH)
    }

    private void buildCenter() {
        // TODO: GridLayout(2, 2, 8, 4) panel
        // Row 1: "Power:" label + powerField
        // Row 2: "Accel.:" label + accelField  
        // + turboCheck below or alongside
    }

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

    private void refresh() {
        // TODO: update statusLabel text
    }

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

2.5 Expected output

After clicking Start then Accelerate (value 50):

Voiture[p=4, demarree=true, v=75.0]

After clicking Stop:

Voiture[p=4, demarree=false, v=0.0]

After entering power 8 and clicking New Voiture:

Voiture[p=8, demarree=false, v=0.0]


Part 3 — Add a Menu (20 min)

Add a JMenuBar to your VoitureUI:

┌─────────────┬──────────────┐
│ File        │ Help         │
├─────────────┤              │
│ Save state  │ About        │
│ ─────────── │              │
│ Exit        │              │
└─────────────┘
Menu item Behaviour
Save state Print voiture.toString() to the console (file I/O from CM2 is optional)
Exit System.exit(0)
About Show JOptionPane.showMessageDialog with the text "Voiture 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 — VoitureSelector — JComboBox (20 min)

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

4.1 Pre-configured fleet

private Voiture[] fleet = {
    new Voiture(4),
    new Voiture(6),
    new Voiture(28, true, 0),
};
private String[] names = {"Clio (p=4)", "Polo (p=6)", "Ferrari (p=28)"};

4.2 Add to CENTER panel

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

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


Part 5 — Exploration (remaining time)

5.1 Make the Accelerate button disabled (setEnabled(false)) when voiture.isEstDemarree() 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