views:

2784

answers:

5

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.

A: 

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);
Richard Campbell
I don't want to do this to all the buttons in my application, too much hassle.
Alfred B. Thordarson
You can subclass JButton and add this in the constructor.
Richard Campbell
A: 

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.

davetron5000
I agree, this would be a nightmare.
Alfred B. Thordarson
+2  A: 

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;
    }
}
Peter Štibraný
Thank you very much Peter. I think the best answers are Code-Based answers. Thumbs up!
Alfred B. Thordarson
+3  A: 

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.

Alfred B. Thordarson
Aah, very nice ;-) Good article too. I looked at MetalLookAndFeel class while working on my answer, and this is just few lines above "Button.focusInputMap" which I used.
Peter Štibraný
A: 

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.

Draemon