In this hands-on session, the objective is to get acquainted with the Swing java library.

The session heavily relies on the official Swing tutorial. The objective of this page is to give you a low friction path through the main concepts in Swing. Concepts are discussed in depth in the documentation and you will also find a wealth of examples that illustrate all concepts.

Main Window (Frame)

You are given the following code as a starting point. Run it on you machine and try to answer the questions below.

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

public class FrameDemo {
    /**
     * Create the GUI and show it.  For thread safety,
     * this method should be invoked from the
     * event-dispatching thread.
     */
    private static void createAndShowGUI() {
        // Create and set up the window.
        JFrame frame = new JFrame("FrameDemo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JLabel emptyLabel = new JLabel("Greetings Swinger");
        emptyLabel.setPreferredSize(new Dimension(175, 100));
        frame.getContentPane().add(emptyLabel, BorderLayout.CENTER);

        // make window's dimension fit its content
        frame.pack();
        // Display the window.
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        // Schedule a job for the event-dispatching thread:
        // creating and showing this application's GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }
}

Questions:

  • Change the title of the window to something more catchy.
  • What is the purpose of the setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE) line? Verify you assumption by removing the line. Is the program still running after closing the window?
  • which line decides the size of the JLabel? What happens if you:
    • remove it?
    • make it smaller than the text?
  • Which line is used to determine the window's size? What happens if you remove it?

A JFrame is a top-level container. Each application has at least one top-level containers in which other components are placed.

JLabel

The label is the most basic component in Swing. It allows displaying short text or images. So far you have used to display a raw text, but it supports several features to control how a text should be displayed, either through the JLabel API or through HTML.

Exercises:

  • Make the label's text centered
  • Make the text of the label red

Having several components in a frame

Each container is associated to layouts that determines how its component are organized in two dimensions:

In the case of the JFrame, the default layout is a BorderLayout

Exercise:

  • In which part of the frame's BorderLayout is our JLabel displayed?

  • Add a new button in the bottom part of the frame (JButton button = new JButton("Click Me!"))

  • What happens if you add more than on component to the part of the layout?

Laying Out Components: grouping with JPanel

Now that we are Swing power-users, we wish to build a real application: a counter. In order to get founding for the start-up, you need an MVP, that:

  • displays the current value of the counter at the center,
  • provides two buttons at the bottom to respectively decrease and increase the counter.

You are now facing a major technical problem: it is impossible to add two components at the bottom of the frame... Luckily an expensive consulting company (McKinsa), gives you the solution:

Indeed, you can only place a single component at the bottom of a BorderLayout. However, when facing this situation you can group your buttons in a JPanel container. This will essentially create a new component containing you two buttons. You can then place it where you want in the frame.

Exercise: Place two buttons "-" and "+" at the bottom of your counter app.

Buttons and events

So far, we have displayed buttons but nothing was happening when clicking on them. This is made possible by the Oberserver design pattern implemented by the buttons.

Each button has a list of ActionListener. Each time an action (e.g. a click) happens on this button, the actionPerformed(...) method of each listener is called; Some context on the action is provided in ActionEvent parameter.

public void actionPerformed(ActionEvent e) { 
    ...// code that reacts to the action... 
}

Exercise: For each button, create an ActionListener that prints MINUS/PLUS to the standard output when the button is clicked.

Custom components

One of the (very few) great things about Object-Oriented Programming is that you can specialize an existing class for your purpose. In GUI programming, this comes extremely handy as it allows providing custom components very easily.

Exercise:

  • Complete the following subclass of JLabel so that it displays the current value of the counter in its text field anytime the counter is updated with the setCounter() method. Note that, like any JLabel, it has a setText(...) method to update the text of
  • Replace the JLabel you previously used in the counter application by your new CounterComponent
  • Update your actions listener to call the decrease()/increase() methods of the component.
static class CounterComponent extends JLabel {
    private int counter = 0;
    public CounterComponent() {
        // set style, dimensions, ...
    }

    void setCounter(int newValue) {
        ...
    }

    void increase() {
        ...
    }

    void decrease() {
        ...
    }
}

Text fields

NASA has a great use case for your counter to serve has the central component for the count-down before launch. Problem is, in the current version, the launch officer has to click 10 times on the + button before starting the countdown.

Exercise: Make the counter editable by using a JTextField instead of a JLabel as the base class for CounterComponent. Make sure that the count number can still be updated with the buttons.

Exercise: Add a new Start Countdown button that would:

  • decrement the counter every second (remember the lab on Threads and Timers)
  • Display a dialog when the countdown reaches 0 (be creative with its content)