TD4 — Swing: Voiture Control Panel
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
JFrameand nestedJPanels - Use
BorderLayout,FlowLayout, andGridLayout - Connect
ActionListenerevents to theVoituremodel from Part 1 - Read and write component values (
JTextField,JLabel,JComboBox) - Use
JMenuBarandJOptionPane
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:
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):
After clicking Stop:
After entering power 8 and clicking New Voiture:
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 |