Java Swing Stupidity, pt. 1

At some point I intend to write a longish post about various application frameworks and where they lie in a spectrum between “high level” and “low level” verses “easy to use” to “hard to use.” In this scheme Java Swing scores higher than AWT, but lower than MFC.

Meanwhile, I have a hint for those trying to put together a Java Swing dialog and they want the escape key to do, well, what an escape key is supposed to do in a dialog box: hit the ‘cancel’ button and close the dialog.

The head scratching problem:

How do I make the escape key press the cancel button?

Answer:

No, Swing doesn’t do this for you. (Stupid, stupid, stupid.)

Instead, you have to add the escape key handler to the root pane’s input map, and add a new action which triggers the appropriate button click.

To elaborate: suppose you have a dialog class which is creating the cancel button. You need to get the root pane of the dialog, then add a mapping to the root pane from the key stroke you wish to intercept to an “action”, then map the action to a specific AbstractAction derived class that handles the specific action.

// (Inside a method that lives inside a JDialog derived class)
// Create and add my new cancel button.
bctl = new JButton("Cancel");
bctl.addActionListener(this);
bctl.setName("cancel");
contents.add(bctl);

// (New) Create escape key stroke ID, add to input map
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE,0);
getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(keyStroke,"Cancel");
// (New) And add a new action to fire my action object.
getRootPane().getActionMap().put("Cancel", new FireButtonClickAction(bctl));

Note that the class FireButtonClickAction is a new class we create below. It takes an argument to the object we’re clicking, and maps it to the specific action–in this case, an action which presses the cancel button for us.

The FireButtonClickAction class itself is very simple:

final class FireButtonClickAction extends AbstractAction
{
  private AbstractButton  fButton;
  
  FireButtonClickAction(AbstractButton button)
  {
    fButton = button;
  }

  public void actionPerformed(ActionEvent e)
  {
    fButton.requestFocusInWindow();
    fButton.doClick(100);       // 1/10 S press time.
  }
}

I use the doClick(int delay); variant to give visual feedback to the user, as is recommended in the original Apple Human User Interface Guidelines. The 1/10th of a second delay isn’t much, but the quick ‘flash’ does tell the user “your dialog box went away because you dismissed it”, verses “your dialog box just went poof–did it crash?”

You can use the same technique to create ‘meta-keys’ on Windows and Unix; these are generally “Alt+X” key combinations which can be used as a keyboard shortcut to activate the function. (You can also do this on the Macintosh; however, I would recommend against it–or at least against making the underline under the meta key not visible on the Mac as it violates the look and feel and makes your application look like crap.)

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s