Question

I'm writing a Java Swing application using the Metal look-and-feel. Every time there is a JButton in my application the user uses the Tab key to move the focus to the button and then hits the Enter key. Nothing happens! If he hits the Space key the button events are fired. How do I assign the Enter key to trigger the same events as the Space key? Thank you for your help.

Was it helpful?

Solution

I found the following:

http://tips4java.wordpress.com/2008/10/25/enter-key-and-button/

Where Rob Camick writes that when using JDK5 and later you simply add...

UIManager.put("Button.defaultButtonFollowsFocus", Boolean.TRUE);

...to the application to solve the problem. This did the trick for me! And I can't imagine anything simpler. However, when using older versions of Java you will have to do something like Richard and Peter describe in their answers to this question.

OTHER TIPS

Here is complete example. Richard was close, but you also need to map pressed ENTER to action, not just released. To make it work for ALL buttons, I have put this mapping to default input map for buttons. Add imports, and it should be runnable.


public class Main implements Runnable {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Main());
    }

    @Override
    public void run() {
        setupEnterActionForAllButtons();

        JFrame frame = new JFrame("Button test");
        frame.getContentPane().add(createButton(), BorderLayout.NORTH);
        frame.getContentPane().add(createButton(), BorderLayout.SOUTH);
        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        frame.setVisible(true);
    }

    private void setupEnterActionForAllButtons() {
        InputMap im = (InputMap) UIManager.getDefaults().get("Button.focusInputMap");
        Object pressedAction = im.get(KeyStroke.getKeyStroke("pressed SPACE"));
        Object releasedAction = im.get(KeyStroke.getKeyStroke("released SPACE"));

        im.put(KeyStroke.getKeyStroke("pressed ENTER"), pressedAction);
        im.put(KeyStroke.getKeyStroke("released ENTER"), releasedAction);
    }

    private JButton createButton() {
        JButton b = new JButton("press enter");
        b.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("Pressed");
            }
        });

        return b;
    }
}

Actually, this is a look and feel issue. It is (and should be) up to the look and feel as to which key triggers the focused button.

The "default button" work-around works since the L&F you're using uses enter for the default button.

Peter's workaround explicitly changes the L&F default "focus action" key - which is somewhat more convincing if you ask me.

I would add that I don't think many users would want to tab to the button then hit enter (most won't even notice the focus indicator) - they want the default action to be the "right" one and work wherever they press enter. This can only be done with input maps as Richard suggests.

I would certainly suggest getting a very clear picture of what your users actually want and expect (preferably with reference to other apps they use) before changing anything globally.

You do it by assigning an input / action map for the Enter key. Something like the following:

// save the command mapping for space
Object spaceMap = button.getInputMap.get(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, true));
// add a mapping from enter to the same command.
button.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, true),spaceMap); 

You can also set the "default button" to the button most recently focussed.

I did this on an application, and all methods of doing this are a nightmare to maintain and debug. The fact is, this is clearly not what the designers of Swing intended to happen.

Extension to above answers to do same with radio , checkboxes. Called this before creating components

void setupEnterAction(String componentName){
    String keyName = componentName + ".focusInputMap";
    InputMap im = (InputMap) UIManager.getDefaults().get(keyName);
    Object pressedAction = im.get(KeyStroke.getKeyStroke("pressed SPACE"));
    Object releasedAction = im.get(KeyStroke.getKeyStroke("released SPACE"));
    im.put(KeyStroke.getKeyStroke("pressed ENTER"), pressedAction);
    im.put(KeyStroke.getKeyStroke("released ENTER"), releasedAction);
}

public void setEnterEvent(){
    setupEnterAction("Button");
    setupEnterAction("RadioButton");
    setupEnterAction("CheckBox");
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top