John,
It's not a bug: JTable registers the escape-keypressed for canceling an
edit.
If you don't allow edit's in the table then you can simply
remove the registration from the
inputMap(WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); note that you actually
have to remove it from the parent map, that is
table.getInputMap(ancesterCondition).getParent().remove(escKeyStroke).
Things get a bit more complicated if you need a two stage "escape" (one
for cancelling the edit without cancelling the dialog, the other for
cancelling the dialog). A keyEvent is consumed if an inputMap is found
that has interest in it. So you need two different keyStrokes (pressed
vs. released) plus dynamic updates of the table's inputMap to handle it.
Attached is a modified version of your sample. It's a quick test to show
the principle, needs some polish for production of course.
Greetings
Jeanette
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
public class JTableEscapeKeyBug extends JDialog {
public static void main(String[] args) {
new JTableEscapeKeyBug();
}
public JTableEscapeKeyBug() {
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}}
);
JButton b = new JButton("Hello");
Object[][] data = {
{"one"},
{"two"},
{"three"}
};
String[] hdr = {"Header"};
JTable table = new JTable(data, hdr);
table.setBorder(BorderFactory.createLoweredBevelBorder());
JTextField tf = new JTextField();
tf.setText("some text");
getContentPane().setLayout(new BorderLayout(10, 10));
getContentPane().add(b, BorderLayout.NORTH);
getContentPane().add(table);
getContentPane().add(tf, BorderLayout.SOUTH);
pack();
setVisible(true);
InputMap map = table.getInputMap(table.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
KeyStroke esc = KeyStroke.getKeyStroke("ESCAPE");
// this is if you want to keep table's ability to cancel edits
Action escAction = table.getActionMap().get(map.get(esc));
Action newAction = new FilteredAction(table, escAction);
table.getActionMap().put("cancel", newAction);
// this is if you want to cancel edits and the dialog at the same time
/* InputMap parent = map.getParent();
System.out.println("parent: " + parent);
parent.remove(esc);
System.out.println("after parent: " + parent.get(esc));
*/
}
public class FilteredAction extends AbstractAction {
Action action;
JComponent comp;
KeyStroke stroke = KeyStroke.getKeyStroke("released ESCAPE");
public FilteredAction(JComponent comp, Action action) {
this.comp = comp;
this.action = action;
}
public void actionPerformed(ActionEvent e) {
if (!comp.hasFocus()) {
comp.getInputMap().put(stroke, "cancel");
action.actionPerformed(e);
} else {
comp.getInputMap().remove(stroke);
}
}
}
protected void showKeys(String message, InputMap map) {
KeyStroke[] keys = map.allKeys();
System.out.println(message);
if (keys != null) {
for (int i = 0; i < keys.length; i++) {
System.out.println(keys[i]);
}
}
}
protected JRootPane createRootPane() {
// Create an actionListener that is used to close the
// dialog in response to the Escape key being hit
ActionListener actionListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
};
JRootPane rootPane = new JRootPane();
rootPane.registerKeyboardAction(
actionListener,
// cancel the dialog on keyReleased instead of keyPressd
KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, true),
JComponent.WHEN_IN_FOCUSED_WINDOW
);
return rootPane;
}
}