When we create GUI objects like buttons and windows, the user can interact with these. A GUI object is considered the source for the events, like mouse clicks, the occur when the user uses them. When an event occurs, the system needs to know what to do with it. It knows what object on the screen was the source of the event, but it doesn't know what you want to do with it.
Each GUI object has a method that handles this. You create a listener class for the GUI object. This class implements the interface for that objects listener. Each GUI object has its own listener interface. This is because each GUI object has its own set of events that it can respond to. For example, a window can be closed, iconified, zoomed to full screen, etc. A button can be clicked, but not iconified.
Once you create a listener object, you use the add listener method on the GUI object to register this listener with the Java runtime system. When an event occurs, the runtime system know which GUI object was the source of the event. It looks in a table to find the listener object that was registered. If there isn't one, the event is ignored. If there is one, then a method is called on the listener object that corresponds to the event. For example, on a WindowListener, there is a windowClosing() method that is called when the window is closed.
It is safe for the runtime to call this method because it knows that the
object that was passed into the registration method on the GUI object
had to implement the correct listener interface
or the program wouldn't have compiled.
What makes all this work is polymorphism and the use of interfaces to define what kind of responses there can be. For example, when a button is pressed, this creates an event. The button object that you created has an instance variable in it to hold a listener object. You can define a listener class that implements the interface. You then define the methods to handle the event in any way you want.
This is a window event handler that will pop up a message box when the window is closed. We don't really need this, but in other projects, we may have to do some cleanup before the window closes.
// windowlisten.java: Create a frame to test window events // since we are handling events and the pop up, we need // these imports import java.awt.*; import java.awt.event.*; import javax.swing.JOptionPane; // a listener has methods that the runtime calls in response to events public class windowlisten implements WindowListener { // events we don't care about but have to implement // to match the interface public void windowDeiconified(WindowEvent event) { } public void windowIconified(WindowEvent event) { } public void windowActivated(WindowEvent event) { } public void windowDeactivated(WindowEvent event) { } public void windowOpened(WindowEvent event) { } public void windowClosed(WindowEvent event) { } public void windowClosing(WindowEvent event) { JOptionPane.showMessageDialog(null, "Window is closing", "Window",JOptionPane.INFORMATION_MESSAGE); } } // windowlisten
Now we need to make a window. We will create a class that extends JFrame. JFrame is a Java GUI class that creates a basic window. Our class will simply have a constructor that sets some properties on the window. Then it will create a listener object and register it with the runtime system.
// simplewindow.java: Create a frame // a frame is a basic window, just the title, close buttons, no contents import javax.swing.JFrame; public class simplewindow extends JFrame { public simplewindow() { // when one of these is created, that makes the window // now we set some of its properties setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // program ends when window closes setTitle("Test Window Event"); // text in title bar setSize(500, 500); // size in pixels setVisible(true); // make sure we can see it // create a listener to handle any events windowlisten w = new windowlisten(); addWindowListener(w); // Register listener // this could be compacted to // addWindowListener( new windowlisten() ); // Register listener } // default constructor } // simplewindow
Now here is the main class that starts everything up.
// listenexample.java: Create a window to test window events import javax.swing.JFrame; public class listenexample { public static void main(String[] args) { System.out.println("starting - setting up window"); simplewindow frame = new simplewindow(); // this does all the work System.out.println("ending - window closed"); } } // listenexampleThis creates the GUI components we are interested in.
The WindowAdapter class is a handy tool that implements the correct interface and has empty methods for all the required methods. Then when you create a new class like this, you just overload the methods you are interested in.
Here is the listener class from above using the adaptor.
// windowlisten.java: use the adapter class // since we are handling events and the pop up, we need // these imports import java.awt.event.*; import javax.swing.JOptionPane; // a listener has methods that the runtime calls in response to events public class windowlisten extends WindowAdapter { public void windowClosing(WindowEvent event) { JOptionPane.showMessageDialog(null, "Window is closing", "Window",JOptionPane.INFORMATION_MESSAGE); } } // windowlistenWe don't need to make the listener class a separate class file. We can make define it as an inner class inside the simplewindow class like this.
public class simplewindow extends JFrame { public simplewindow() { // when one of these is created, that makes the window // now we set some of its properties setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // program ends when window closes setTitle("Test Window Event"); // text in title bar setSize(500, 500); // size in pixels setVisible(true); // make sure we can see it // Since this object is a listener, we can register it with the runtime addWindowListener( new windowlisten() ); // Register listener } // default constructor private class windowlisten extends WindowAdapter { public void windowClosing(WindowEvent event) { JOptionPane.showMessageDialog(null, "Window is closing", "Window",JOptionPane.INFORMATION_MESSAGE); } } // windowlisten } // simplewindowNote that the inner class is private. We are only using it inside the simplewindow class. When this class gets compiled, there will be two class files, one for the simplewindow class and one for the windowlisten class.
Now for the weird part. Since a class can extend one other class and implement multiple interfaces, we can create a class that extends JFrame to create the window and implements WindowListener so it can act as the listener for itself. In this case, we don't need the windowlisten class, just the simplewindow class like this.
// simplewindow.java: Create a frame // a frame is a basic window, just the title, close buttons, no contents import java.awt.event.*; import javax.swing.JFrame; import javax.swing.JOptionPane; public class simplewindow extends JFrame implements WindowListener { public simplewindow() { // when one of these is created, that makes the window // now we set some of its properties setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // program ends when window closes setTitle("Test Window Event"); // text in title bar setSize(500, 500); // size in pixels setVisible(true); // make sure we can see it // Since this object is a listener, we can register it with the runtime addWindowListener(this); // Register listener } // default constructor // now we implement the interface routines like windowlisten did // events we don't care about but have to implement // to match the interface public void windowDeiconified(WindowEvent event) { } public void windowIconified(WindowEvent event) { } public void windowActivated(WindowEvent event) { } public void windowDeactivated(WindowEvent event) { } public void windowOpened(WindowEvent event) { } public void windowClosed(WindowEvent event) { } public void windowClosing(WindowEvent event) { JOptionPane.showMessageDialog(null, "Window is closing", "Window",JOptionPane.INFORMATION_MESSAGE); } } // simplewindow
Now for the weirder part. We are creating the windowlisten class just to create exactly one instance and to immediately pass it into the addWindowListener() method on the simplewindow class. Java provides a way to do this with even less overhead than the inner class technique. We can define the class and create an instance inside the call to addWindowListener() method.
// simplewindow.java: Create a frame // a frame is a basic window, just the title, close buttons, no contents import java.awt.event.*; import javax.swing.JFrame; import javax.swing.JOptionPane; public class simplewindow extends JFrame { public simplewindow() { // when one of these is created, that makes the window // now we set some of its properties setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // program ends when window closes setTitle("Test Window Event"); // text in title bar setSize(500, 500); // size in pixels setVisible(true); // make sure we can see it // Since this object is a listener, we can register it with the runtime addWindowListener( new WindowAdapter() { public void windowClosing(WindowEvent event) { JOptionPane.showMessageDialog(null, "Window is closing", "Window",JOptionPane.INFORMATION_MESSAGE); } } // windowlisten ); // Register listener } // default constructor } // simplewindowThe syntax here is a little unexpected.
When compiled, we still get an extra class file, but there is less coding overhead.