Background: I have a table cell editor that when invoked pops up a dialog with a list of checkboxes, and 2 buttons (OK and Cancel). All works well. I later registered keyboard actions so that the ENTER and ESCAPE keys would perform the ok/cancel actions. Still no problems.
Using the same technique, I tried to register the SPACE key to do a third action. This didn't fire. Sample code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class DialogTest implements Runnable
{
JDialog dialog;
JList jlist;
public static void main(String[] args)
{
SwingUtilities.invokeLater(new DialogTest());
}
public void run()
{
ActionListener okListener = new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
close(true);
}
};
ActionListener cancelListener = new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
close(false);
}
};
ActionListener otherListener = new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
doOther();
}
};
JButton okButton = new JButton("OK");
okButton.addActionListener(okListener);
JButton cancelButton = new JButton("Cancel");
cancelButton.addActionListener(cancelListener);
jlist = new JList(new String[]{"A", "B", "C", "D", "E", "F", "G"});
jlist.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
jlist.setVisibleRowCount(5);
JScrollPane scroll = new JScrollPane(jlist);
scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
JPanel buttonsPanel = new JPanel(new FlowLayout());
buttonsPanel.add(okButton);
buttonsPanel.add(cancelButton);
JPanel content = new JPanel(new BorderLayout());
content.add(scroll, BorderLayout.CENTER);
content.add(buttonsPanel, BorderLayout.SOUTH);
dialog = new JDialog((Frame) null, true);
dialog.setContentPane(content);
dialog.pack();
dialog.setLocationRelativeTo(null);
dialog.getRootPane().registerKeyboardAction(okListener,
KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0),
JComponent.WHEN_IN_FOCUSED_WINDOW);
dialog.getRootPane().registerKeyboardAction(cancelListener,
KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0),
JComponent.WHEN_IN_FOCUSED_WINDOW);
// This doesn't work
dialog.getRootPane().registerKeyboardAction(otherListener,
KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0),
JComponent.WHEN_IN_FOCUSED_WINDOW);
dialog.setVisible(true);
}
private void close(boolean commit)
{
if (commit)
{
System.out.println("Now saving...");
}
else
{
System.out.println("Now closing...");
System.exit(0);
}
}
private void doOther()
{
System.out.println("current selection: " + jlist.getSelectedValue());
}
}
EDIT
Thanks to mKorbel's suggestion (and useful link!), I got this to work:
1) Change the line ActionListener otherListener = new ActionListener(){...}
to:
Action otherListener = new AbstractAction(){...}
2) Change the SPACE keystroke registration to:
KeyStroke keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0);
Object key = keyStroke.toString();
jlist.getInputMap().put(keyStroke, key);
jlist.getActionMap().put(key, otherAction);
Note that the registration is for the JList, not the JDialog as the other 2 keystrokes are.
hard to say whatever cleaver to your majesty ....
EDIT
I forgot about SPACE is registred KeyBindings as humans JButtons accelerator (Mouse, ENTER & SPACE), there is possible concurency if JButton is selected
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class DialogTest implements Runnable {
private JDialog dialog;
private JList jlist;
public static void main(String[] args) {
SwingUtilities.invokeLater(new DialogTest());
}
@Override
public void run() {
ActionListener okListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
close(true);
}
};
ActionListener cancelListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
close(false);
}
};
ActionListener otherListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
doOther();
}
};
JButton okButton = new JButton("OK");
okButton.addActionListener(okListener);
JButton cancelButton = new JButton("Cancel");
cancelButton.addActionListener(cancelListener);
jlist = new JList(new String[]{"A", "B", "C", "D", "E", "F", "G"});
jlist.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
jlist.setVisibleRowCount(5);
JScrollPane scroll = new JScrollPane(jlist);
scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
JPanel buttonsPanel = new JPanel(new FlowLayout());
buttonsPanel.add(okButton);
buttonsPanel.add(cancelButton);
JPanel content = new JPanel(new BorderLayout());
content.add(scroll, BorderLayout.CENTER);
content.add(buttonsPanel, BorderLayout.SOUTH);
dialog = new JDialog((Frame) null, true);
dialog.setContentPane(content);
dialog.pack();
dialog.setLocationRelativeTo(null);
dialog.getRootPane().registerKeyboardAction(okListener,
KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0),
JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
dialog.getRootPane().registerKeyboardAction(cancelListener,
KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0),
JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
// This doesn't work
/*dialog.getRootPane().registerKeyboardAction(otherListener,
KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0),
JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);*/
dialog.getRootPane().getInputMap().put(KeyStroke.getKeyStroke("SPACE"), "doSomething");
dialog.getRootPane().getActionMap().put("doSomething", new AbstractAction() {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
dialog.setVisible(true);
}
private void close(boolean commit) {
if (commit) {
System.out.println("Now saving...");
} else {
System.out.println("Now closing...");
System.exit(0);
}
}
private void doOther() {
System.out.println("current selection: " + jlist.getSelectedValue());
}
}