theUg
theUg

Reputation: 1314

Key binding does not work

I have JButton performing some action via ActionListener. After I try to use Action to bind a keyboard shortcut (following this), mouse click on button works, but no reaction to keyboard.

Code Before

Button created within a panel, actionListener added.

private FooActionListener actionListener = new FooActionListener();

buttonLeft = new JButton("Left");
up.addActionListener(actionListener);

Then, actionPerformed method within FooActionListener class outside the main class:

public void actionPerformed(ActionEvent e) {
    Object source = e.getSource();
    if (source == buttonLeft) { thing.move(Direction.LEFT); }
}

Code After

final String leftText = "Left";
final Action left = new AbstractAction() {

    @Override
    public void actionPerformed(ActionEvent e) {
        thing.move(Direction.LEFT);
    }
};

buttonLeft = new JButton(left);
buttonLeft.setText(leftText);
KeyStroke keyLeft = KeyStroke.getKeyStroke(KeyEvent.VK_A, 0);
buttonLeft.getInputMap(buttonLeft.WHEN_IN_FOCUSED_WINDOW).put(keyLeft,
    "Left");
buttonLeft.getActionMap().put("Left", left );

Update: I am not quite sure that new code actually performs with the mouse as it should. Let’s say the object supposed to move 25 pixels by one click, and it does in the original code. But with the new action it seems that it moves twice or even trice with each click, which suggests some weird behavior of an action.

Upvotes: 2

Views: 890

Answers (1)

MadProgrammer
MadProgrammer

Reputation: 347194

It's possible that the button is absorbing you mappings, I would, however, do it slightly differently.

Because you've used an Action (correctly), you movement logic is mostly centralised already.

I would simply apply the mappings to the main container instead.

public class TestKeybindings01 {

    public static void main(String[] args) {
        new TestKeybindings01();
    }

    public TestKeybindings01() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private JLabel label;
        private JButton left;
        private JButton right;

        public TestPane() {

            label = new JLabel("Make a choice");
            label.setHorizontalAlignment(JLabel.CENTER);

            LeftAction leftAction = new LeftAction(label);
            RightAction rightAction = new RightAction(label);

            InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0), "left");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0), "right");

            ActionMap am = getActionMap();
            am.put("left", leftAction);
            am.put("right", rightAction);

            left = new JButton(leftAction);
            right = new JButton(rightAction);

            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridx = 0;
            gbc.gridy = 0;
            gbc.gridwidth = 2;
            gbc.anchor = GridBagConstraints.CENTER;
            gbc.fill = GridBagConstraints.HORIZONTAL;
            add(label, gbc);

            gbc.gridy++;
            gbc.gridwidth = 1;
            add(left, gbc);
            gbc.gridx++;
            add(right, gbc);


        }

    }

    public abstract class AbstractDirectionAction extends AbstractAction {

        private JLabel label;

        public AbstractDirectionAction(JLabel label) {
            this.label = label;
        }

        public JLabel getLabel() {
            return label;
        }

        public void setDirection(String text) {
            getLabel().setText(text);
        }

    }

    public class LeftAction extends AbstractDirectionAction {

        public LeftAction(JLabel label) {
            super(label);
            putValue(NAME, "<<");
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            setDirection("Left");
        }

    }

    public class RightAction extends AbstractDirectionAction {

        public RightAction(JLabel label) {
            super(label);
            putValue(NAME, ">>");
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            setDirection("Right");
        }

    }

}

Upvotes: 2

Related Questions