Basic Swing concepts: events and listeners

In our introduction to Swing, we saw a very basic user interface program that popped up a blank window. But apart from popping up the window, it didn't really "do" very much. To start making our user interface "do" things, we have to start thinking in terms of events.

In any GUI-based program1, a lot of the functionality comes from responding to events: mouse clicks, button clicks, key presses etc. So the first challenge with GUI programming is often turning the program flow that we have in our head into an event-based flow. The basic idea of an event-based approach is that:

As an illustration, we're going to modify our program to do the following:

Figure 1 Simple frame with button added.

Adding a button to the window

First, the easy bit: adding the button to our window. Adding a button to the window is essentially like adding most other components. All components— buttons, lists, tables, checkboxes etc— are represented by classes inside the javax.swing package, with a class name beginning with J. We've already seen that a "window"— stictly speaking called a frame when it has decorations— is represented by the JFrame class. To create a button, we similarly create an instance of a class called... wait for it... JButton. As with many Swing classes, the constructor can take some common parameters, in particular, the label (the text that appears on the button):

JButton butt = new JButton("Click me!");

This is all well and good, but we haven't actually put the button inside our frame (or indeed, anywhere) yet. To add the button to the frame, we use the frame's add() method:

frame.add(butt);

By default, the button will occupy the whole of the window. Later, we'll see how to specify where we want the button adding and rationalise its size; we won't worry about that for now. Instead, we'll just make the frame a bit smaller (say, 200 by 100 pixels), so the button doesn't look too ridiculous. The full main() method now looks like this, and running it should give something as shown in Figure 1:

public static void main(String[] args) {
  JFrame frame = new JFrame("My Swing app");
  frame.setSize(200, 100);
  frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  JButton butt = new JButton("Click me!");
  frame.add(butt);
  frame.setVisible(true);
}

"Waiting" for a button click: listeners

So now, we want to wait for a button click. Or more precisely, we're going to let the UI system worry about "waiting". What we're going to do is register a piece of code, saying "this is the code to call when X happens". In our case, we're specifically going to say to the system: "please call this method when this button is clicked". To do so, we're going to use a listener.

A listener is a class that has methods that are called when various "interesting things" happen. For example, a mouse listener might have one method that's called when the mouse is clicked, another when the mouse is dragged etc. For responding to button presses, we actualy want something called an action listener. Inside the java.awt.event package, there's an interface called ActionListener:

public interface ActionListener extends EventListener {

  public void actionPerformed(ActionEvent e);

}

Remember, the point of an interface is that we can take any old class and, provided we add definitions of the required methods to that class— in this case, there's just the one actionPerformed() method— we can then say that that class implements the interface. So we can write the following (for now, we'll gloss over the showMessageDialog() method: you can probably guess more or less what it does...):

class MyListener implements ActionListener {

  public void actionPerformed(ActionEvent e) {
    JOptionPane.showMessageDialog(null, "You clicked me!");
  }

}

Now, we can create an instance of MyListener, and register it with our button. This will mean that the listener's actionPerformed() method will be called whenever the button is clicked. To register a listener with the button, we use the button's addActionListener() method:

ActionListener listener = new MyListener();
butt.addActionListener(listener);

If you put these fragments together and run the program, you should find that the button responds to a click as expected.

Waiting != waiting

One thing that some beginners find unintuitive is that there's no line of code where we implicitly sit in a loop "waiting" for the click to occur. That's handled by Swing itself (and deep down, by the underlying GUI component of the OS). So in a simple program like this, once we've set up our frame, our main method exits, and there's essentially no actual line of our program running until the button click occurs.

Why doesn't the program exit?

If you're wondering, "how comes our program doesn't exit if the main method has exited", the answer is essentially "because Swing makes sure it doens't":

Once you display the first Swing component in your application, from that moment onwards, you will need to explicitly exit the program by calling System.exit() (or by having a window that auto-exits the application, as in our example).

Next: anonymous inner classes

On the next page, we look at a syntactic trick called anonymous inner classes. After that, we move on to two other important types of component: JTextField and JLabel.


1. You've probably come across the acronynm GUI, standing for Graphical User Interface, and UI or User Interface. We're essentially going to use the terms User Interface, UI and GUI interchangeably. It's conceivable— though nowadays rare— to have a user interface that isn't necessarily "graphical". And conceivably, you could use UI to cover non-visual aspects, such as voice input/output, and reserve the term GUI for those aspects that are strictly graphical. But it's not clear that the terms are really used with much distinction, and for our purpose, the distinction isn't terribly relevant.


If you enjoy this Java programming article, please share with friends and colleagues. Follow the author on Twitter for the latest news and rants.

Editorial page content written by Neil Coffey. Copyright © Javamex UK 2021. All rights reserved.