Extending Swing via Listeners
  Posted May 25, 2004    PermaLink    Comments (1)  

With a framework as nimble as Swing there are many ways to skin a cat. This is possibly one of the sources of many complains about Swing. For example Sam Dalton wrote a class that implements a dialog that closes when the escape key is pressed. Subclassing JDialog is certainly one way t do it, but I probably would have simply wrote a utility method...

static void makeDisposeOnEscapeKey(final RootPaneContainer rootPane) { Action action = new AbstractAction() { public void actionPerformed(ActionEvent arg0) { ((java.awt.Window)rootPane).dispose(); } }; KeyStroke stroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0); rootPane.getRootPane() .getActionMap() .put(action,action); rootPane.getRootPane() .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) .put(stroke, action); }

A couple of changes reflect my swing codeing preferences. First, I call dispose() instead of hide(). My reasons are twofold: first until a window is disposed it takes up native graphics resources, and can essentially be a big memory leak until the object becomes inaccessible and is finalized. The second reason has to do with a clean JVM exit. While any AWT resources are realized (i.e. have native OS resources allocated) the AWT event thread will keep running and the JVM will not exit. If all of the windows are disposed() then the AWT event thread will enter a state that will allow the JVM to terminate. No more calls to System.exit(0).

The second thing I changed was which action map I put the escape key in. Sam used WHEN_FOCUSED which is fine if there are no focusable components in the dialog. But throw in a button or text field and the action may never get fired. There are actually two options here, WHEN_ANCESTOR_OF_FOCUSED_COMPONENT and WHEN_IN_FOCUSED_WINDOW. I chose the latter because this is also how the JMenuItems register their accelerator keys and the desired operation is essentially the same. Since we are adding the action to the JRootPane there are no differences between the two.

By using a utility method we can also add this behavior to any free standing component. One of the issues Swing has to deal with is that higher up in the AWT hierarchy dialogs and frames were separated. To deal with this they created an interface javax.swing.RootPaneContainer so that they can treat all root level components the same. Hence this behavior can be added to any JFrame, JDialog, JWindow, JApplet, or JInternalFrame.

And please, if you have obnoxious splash screens either have a user preference to turn it off or add this to the JWindow so the user can click it and press escape. Wouldn't that be nice.

Trackback URL
  TrackBack URL for this entry:
Name:Eric Snell
Date:May 26, 2004 07:39 AM

I also use this style. One thing, I don't dispose of the window, I instead send it a close event. That keeps the logic of what to do with the close in the setDefaultCloseOperation() setting.

eg. frame.dispatchEvent(new WindowEvent(frame, WindowEvent.WINDOW_CLOSING));

Post Comment

Thanks for signing in, . Now you can comment. (sign out)

(If you haven't left a comment here before, you may need to be approved by the site owner before your comment will appear. Until then, it won't appear on the entry. Thanks for waiting.)

Remember me?

Email Address: