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:
- most of the time, our program does nothing;
- the "system" will call routines that we have written when
"interesting things" happen (mouse clicks etc).
As an illustration, we're going to modify our program to do the following:
- add a button to our window;
- wait for the user to click the button;
- when the user clicks a button, pop up a message.
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:
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.