Why does Jtoolbar break my keyBindings?

别等时光非礼了梦想. 提交于 2019-12-24 13:10:53

问题


I have been trying to use the arrow keys as part of my application. Following the best practice I have stuck with using key bindings. I gound that the arow keys do not produce a key typed event so I employed this answer.

However, my application has a number of components and I found that if I have a JToolbar in my JFrame the method in the previous link no longer works. Why is this and how do I have a JToolbar and use key bindings?

Here is a SSCCE

public class ArrowTest extends JFrame {

    public static void main(final String[] args){
        final ArrowTest at = new ArrowTest();
        at.setSize(100,200);

        final JPanel jp = new JPanel();
        jp.setBackground(Color.BLUE);
        at.getContentPane().add(jp);
        final JToolBar toolbar = new JToolBar();
        toolbar.add(new JButton());
        //at.add(toolbar);
        at.setVisible(true);
    }

    public ArrowTest() {
        super();    
        this.getContentPane().setLayout(new GridBagLayout());    
        this.getContentPane().setBackground(Color.BLACK);    
        this.setKeyBindings();
    }

    public void setKeyBindings() {

        final int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;    
        final ActionMap actionMap = this.getRootPane().getActionMap();
        final InputMap inputMap = this.getRootPane().getInputMap(condition);

        for (final Direction direction : Direction.values()) {
            inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_V,0), direction.getText());
            inputMap.put(direction.getKeyStroke(), direction.getText());
            actionMap.put(direction.getText(), new MyArrowBinding(direction.getText()));
        }

    }

    enum Direction {
        UP("Up", KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0)),
        DOWN("Down", KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0)),
        LEFT("Left", KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0)),
        RIGHT("Right", KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0));

        Direction(final String text, final KeyStroke keyStroke) {
            this.text = text;
            this.keyStroke = keyStroke;
        }
        private String text;
        private KeyStroke keyStroke;

        public String getText() {
            return text;
        }

        public KeyStroke getKeyStroke() {
            return keyStroke;
        }

        @Override
        public String toString() {
            return text;
        }
    }

    private class MyArrowBinding extends AbstractAction {

        private static final long serialVersionUID = -6904517741228319299L;

        public MyArrowBinding(final String text) {
            super(text);
            putValue(ACTION_COMMAND_KEY, text);
        }

        @Override
        public void actionPerformed(final ActionEvent e) {
            final String actionCommand = e.getActionCommand();
            System.out.println("Key Binding: " + actionCommand);
        }
    }    
}

回答1:


By default, JToolBar registers an action for the KeyStroke's UP/DOWN/LEFT/RIGHT, and the JToolBar you add to the JFrame automatically grabs the focus, hence you don't see anything when binding to the rootpane (the toolbar catches the events before you).

One solution is to make the JToolBar and the JButton not focusable and allow your JPanel to be focusable (actually you could leave the JToolBar and the JButton and request the focus on your panel but this also means that you have to handle the focus management of your panel):

import java.awt.Color;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;

import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JToolBar;
import javax.swing.KeyStroke;

public class ArrowTest extends JFrame {

    public static void main(final String[] args) {
        final ArrowTest at = new ArrowTest();
        at.setSize(100, 200);

        final JPanel jp = new JPanel();
        jp.setBackground(Color.BLUE);
        jp.setFocusable(true);
        at.getContentPane().add(jp);
        final JToolBar toolbar = new JToolBar();
        JButton comp = new JButton();
        toolbar.add(comp);
        at.add(toolbar);
        at.setVisible(true);
    }

    public ArrowTest() {
        super();
        this.getContentPane().setLayout(new GridBagLayout());
        this.getContentPane().setBackground(Color.BLACK);
        this.setKeyBindings();
    }

    public void setKeyBindings() {
        for (final Direction direction : Direction.values()) {
            MyArrowBinding binding = new MyArrowBinding(direction.getText());
            getRootPane().registerKeyboardAction(binding, direction.getText(), direction.getKeyStroke(),
                    JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
        }
    }

    enum Direction {
        UP("Up", KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0)), DOWN("Down", KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0)), LEFT("Left",
                KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0)), RIGHT("Right", KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0));

        Direction(final String text, final KeyStroke keyStroke) {
            this.text = text;
            this.keyStroke = keyStroke;
        }

        private String text;
        private KeyStroke keyStroke;

        public String getText() {
            return text;
        }

        public KeyStroke getKeyStroke() {
            return keyStroke;
        }

        @Override
        public String toString() {
            return text;
        }
    }

    private class MyArrowBinding extends AbstractAction {

        private static final long serialVersionUID = -6904517741228319299L;

        public MyArrowBinding(final String text) {
            super(text);
            putValue(ACTION_COMMAND_KEY, text);
        }

        @Override
        public void actionPerformed(final ActionEvent e) {
            final String actionCommand = e.getActionCommand();
            System.out.println("Key Binding: " + actionCommand);
        }
    }
}

I also replaced your calls to getActionMap/getInputMap by a single call to javax.swing.JComponent.registerKeyboardAction(ActionListener, String, KeyStroke, int)




回答2:


Following the advice in this answer I have solved the issue using

public void setKeyBindings() {

    final int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;    
    final ActionMap actionMap = this.getRootPane().getActionMap();
    final InputMap inputMap = this.getRootPane().getInputMap(condition);

    for (final Direction direction : Direction.values()) {
        inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_V,0), direction.getText());
        inputMap.put(direction.getKeyStroke(), direction.getText());
        actionMap.put(direction.getText(), new MyArrowBinding(direction.getText()));
    }

    condition = JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT;

    actionMap = toolbar.getActionMap();
    inputMap = toolbar.getInputMap(condition);


    for (final Direction direction : Direction.values()) {
        inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_V,0), direction.getText());
        inputMap.put(direction.getKeyStroke(), direction.getText());
        actionMap.put(direction.getText(), new MyArrowBinding(direction.getText()));
    } 


}


来源:https://stackoverflow.com/questions/17047625/why-does-jtoolbar-break-my-keybindings

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!