Recipe 14.6 Terminating a Program with"Window Close"ProblemNothing happens when you click on the close button on the titlebar of an AWT Frame . When you do this on a Swing JFrame, the window disappears but the application does not exit. SolutionUse JFrame's setDefaultCloseOperation( ) method or add a WindowListener and have it exit the application. DiscussionMain windows subclasses of java.awt.Window , such as (J)Frames and (J)Dialogs are treated specially. Unlike all other Component subclasses, Window and its subclasses are not initially visible. This is sensible, as they have to be packed or resized, and you don't want the user to watch the components getting rearranged. Once you call a Window's setVisible(true) method, all components inside it become visible. You can listen for WindowEvents on a Window. The WindowListener interface contains a plenitude of methods to notify a listener when anything happens to the window. You can be told when the window is activated (gets keyboard and mouse events) or deactivated. Or you can find out when the window is iconified or deiconified: these are good times to suspend and resume processing, respectively. You can be notified the first time the window is opened. And, most importantly for us, you can be notified when the user requests that the window be closed. (Some sample close buttons are shown in Figure 14-4.) You can respond in two ways. With Swing's JFrame, you can set the "default close operation." Alternatively, with any Window subclass, you can provide a WindowListener to be notified of window events. In some cases, you may not need a window closer. The Swing JFrame has a setDefaultCloseOperation( ) method, which controls the default behavior. You can pass it one of the values defined in the Swing WindowConstants class:
The action set by setDefaultCloseOperation( ) will be performed after the last windowClosing( ) method on the Window (if you have one) returns. The windowClosing( ) method of your WindowListener is called when the user clicks on the close button (this depends on the window system and, on X Windows, on the window manager) or sends the close message from the keyboard (normally Alt-F4). Figure 14-4. Some close buttons![]() The method signature is: public void windowClosing(WindowEvent); But this method comes from the interface WindowListener , which has half a dozen other methods. If you define a WindowListener and implement only this one method, the compiler declares your class abstract and refuses to instantiate it. You might start by writing stub or dummy versions ( methods whose body is just the two characters {}), but you'd then be doing more work than necessary; an "adapter" class already does this for all methods in the Listener interface. So you really need only to subclass from WindowAdapter and override the one method, windowClosing, that you care about. Figure 14-5 shows this model. Figure 14-5. WindowListener, WindowAdapter, and my WindowCloser![]() Let's put this all together in some code examples. Class WindowDemo puts up a frame and closes when you ask it to. The online source includes class WindowDemo2, which is the same, but implemented as a Swing JFrame. import java.awt.*; import java.awt.event.*; /* Show an example of closing a Window. */ public class WindowDemo extends Frame { public static void main(String[] argv) { Frame f = new WindowDemo( ); f.setVisible(true); } public WindowDemo( ) { setSize(200, 100); addWindowListener(new WindowDemoAdapter( )); } /** Named Inner class that closes a Window. */ class WindowDemoAdapter extends WindowAdapter { public void windowClosing(WindowEvent e) { System.out.println("Goodbye!"); WindowDemo.this.setVisible(false); // window will close WindowDemo.this.dispose( ); // and be freed up. System.exit(0); } } } Since making a Window close and optionally exit the program is a common operation, I've encapsulated this into a small class called WindowCloser , which is in my public package com.darwinsys.util. Most AWT and Swing books have similar classes. Example 14-3 contains my WindowCloser class. Note that the class is marked deprecated; this is to remind you that, on Swing, you should just use setDefaultCloseOperation( ). If you're writing an AWT-only application, you'll have to live with the deprecation warning. Example 14-3. WindowCloser.javapackage com.darwinsys.swingui; import java.awt.Window; import java.awt.event.*; /** A WindowCloser - watch for Window Closing events, and * follow them up with setVisible(false) and dispose( ). * @deprecated Use setDefaultCloseOperation( ) instead. */ public class WindowCloser extends WindowAdapter { /** True if we are to exit as well. */ boolean doExit = false; public WindowCloser( ) { public WindowCloser(Window w) { // nothing to do } public WindowCloser(Window w, boolean exit) { doExit = exit; } public void windowClosing(WindowEvent e) { Window win = e.getWindow( ); win.setVisible(false); win.dispose( ); if (doExit) System.exit(0); } } Using it is straightforward: import java.awt.Frame; import java.awt.Label; import com.darwinsys.swingui.WindowCloser; /* Show an example of closing a Window. */ public class WindowCloserTest { /* Main method */ public static void main(String[] argv) { Frame f = new Frame("Close Me"); f.add(new Label("Try Titlebar Close", Label.CENTER)); f.setSize(100, 100); f.setVisible(true); f.addWindowListener(new WindowCloser(f, true)); } } Notice that some of this "quick and dirty" class extends Frame or JFrame directly. It is generally better to have a main program that creates a JFrame and installs the "main" GUI component into that. This scheme promotes greater reusability. For example, if your graphing program's main component extends JComponent, it can be added to a JPanel in another application; whereas if it extends JFrame, it cannot. See AlsoI've mentioned dispose( ) several times without saying much about it. The dispose( ) method (inherited from Window) causes the underlying (operating system-specific) window system resources to be released without totally destroying the Window. If you later call pack( ) or setVisible(true) on the Window, the native resources are recreated. It's a good idea to dispose( ) a window if you won't be using it for a while, but not if there's a good chance you'll need it again soon. In addition to WindowListener, Swing has several other multimethod interfaces, including MouseListener and ComponentListener, and an Adapter class for each of these. |