即使选择了JTextField,也使箭头键KeyBindings仍然有效

时间:2018-08-04 05:12:15

标签: java swing focus jtextfield key-bindings

我使用的是KeyBindings,并且使用的条件为WHEN_IN_FOCUSED_WINDOW,因此这些键始终有效。但是,如果选择了JTextField,则似乎箭头键(左,右,上,下)的键绑定似乎停止工作。

简而言之,无论JComponent专注于什么,我都希望KeyBindings始终可以工作。

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;

import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.Timer;
import javax.swing.WindowConstants;

public class Test extends JPanel implements ActionListener {
    private static final long serialVersionUID = 1L;

    private static JTextField field;

    private static JFrame frame;

    private static boolean up = false, down = false, left = false, right = false;

    private static int x = 275, y = 275;

    public static void main(String[] args) {
        Test t = new Test();
        t.setBounds(0, 0, 1200, 600);
        t.setVisible(true);

        field = new JTextField();
        field.setBounds(20, 20, 100, 20);

        Timer repaintTimer = new Timer(2, t);

        frame = new JFrame();
        frame.setSize(600, 600);

        setUpKeyActions(t);

        frame.add(field);
        frame.add(t);

        Dimension dim = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setLocation((dim.width - frame.getWidth()) / 2, (dim.height - frame.getHeight()) / 2);
        frame.getContentPane().setLayout(null);
        frame.setAlwaysOnTop(true);
        frame.setResizable(false);

        repaintTimer.start();

        frame.setVisible(true);
        frame.requestFocus();
    }

    private static void setUpKeyActions(Test t) {
        int condition = WHEN_IN_FOCUSED_WINDOW;

        new KeyAction(t, condition, KeyEvent.VK_UP, 0, false) {
            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                up = true;
            }

        };

        new KeyAction(t, condition, KeyEvent.VK_UP, 0, true) {
            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                up = false;
            }

        };

        new KeyAction(t, condition, KeyEvent.VK_LEFT, 0, false) {
            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                left = true;
            }

        };

        new KeyAction(t, condition, KeyEvent.VK_LEFT, 0, true) {
            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                left = false;
            }

        };

        new KeyAction(t, condition, KeyEvent.VK_RIGHT, 0, false) {
            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                right = true;
            }

        };

        new KeyAction(t, condition, KeyEvent.VK_RIGHT, 0, true) {
            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                right = false;
            }

        };

        new KeyAction(t, condition, KeyEvent.VK_DOWN, 0, false) {
            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                down = true;
            }

        };

        new KeyAction(t, condition, KeyEvent.VK_DOWN, 0, true) {
            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                down = false;
            }

        };

    }

    private static abstract class KeyAction extends AbstractAction {
        private static final long serialVersionUID = 1L;

        KeyAction(JComponent component, int condition, int keyCode, int modifiers, boolean onKeyRelease) {
            InputMap inputMap = component.getInputMap(condition);
            ActionMap actionMap = component.getActionMap();
            KeyStroke keyStroke = KeyStroke.getKeyStroke(keyCode, modifiers, onKeyRelease);
            inputMap.put(keyStroke, keyStroke.toString());
            actionMap.put(keyStroke.toString(), this);
        }

    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        if(up)
            y -= 1;
        if(down)
            y += 1;
        if(right)
            x += 1;
        if(left)
            x -= 1;
        if(x < 0)
            x = 0;
        else if(x > frame.getWidth() - 30)
            x = frame.getWidth() - 30;
        if(y < 0)
            y = 0;
        else if(y > frame.getHeight() - 50)
            y = frame.getHeight() - 50;
        g.drawRect(x, y, 30, 30);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        frame.repaint();
    }

}

在上面的代码中,该框随箭头键移动。但是,如果选择左上角的文本框,则该框将不再移动。

更新

我试图按照@camickr的答案在JTextFields中添加KeyBindings,但是它似乎没有用。也许我做错了什么?

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;

import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.Timer;
import javax.swing.WindowConstants;

public class Test extends JPanel implements ActionListener {
    private static final long serialVersionUID = 1L;

    private static JFrame frame;

    private static boolean up = false, down = false, left = false, right = false;

    private static int x = 275, y = 275;

    public static void main(String[] args) {
        Test t = new Test();
        t.setBounds(0, 0, 1200, 600);
        t.setVisible(true);

        JTextField field = new JTextField();
        field.setBounds(20, 20, 100, 20);

        Timer repaintTimer = new Timer(2, t);

        frame = new JFrame();
        frame.setSize(600, 600);

        setUpKeyActions(t, field);

        frame.add(field);
        frame.add(t);

        Dimension dim = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setLocation((dim.width - frame.getWidth()) / 2, (dim.height - frame.getHeight()) / 2);
        frame.getContentPane().setLayout(null);
        frame.setAlwaysOnTop(true);
        frame.setResizable(false);

        repaintTimer.start();

        frame.setVisible(true);
        frame.requestFocus();
    }

    private static void setUpKeyActions(Test t, JTextField field) {
        int condition = WHEN_IN_FOCUSED_WINDOW;

        new KeyAction(condition, KeyEvent.VK_UP, 0, false, t, field) {
            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                up = true;
            }

        };

        new KeyAction(condition, KeyEvent.VK_UP, 0, true, t, field) {
            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                up = false;
            }

        };

        new KeyAction(condition, KeyEvent.VK_LEFT, 0, false, t, field) {
            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                left = true;
            }

        };

        new KeyAction(condition, KeyEvent.VK_LEFT, 0, true, t, field) {
            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                left = false;
            }

        };

        new KeyAction(condition, KeyEvent.VK_RIGHT, 0, false, t, field) {
            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                right = true;
            }

        };

        new KeyAction(condition, KeyEvent.VK_RIGHT, 0, true, t, field) {
            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                right = false;
            }

        };

        new KeyAction(condition, KeyEvent.VK_DOWN, 0, false, t, field) {
            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                down = true;
            }

        };

        new KeyAction(condition, KeyEvent.VK_DOWN, 0, true, t, field) {
            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                down = false;
            }

        };

    }

    private static abstract class KeyAction extends AbstractAction {
        private static final long serialVersionUID = 1L;

        KeyAction(int condition, int keyCode, int modifiers, boolean onKeyRelease, JComponent component, JComponent... components) {
            InputMap inputMap = component.getInputMap(condition);
            ActionMap actionMap = component.getActionMap();
            KeyStroke keyStroke = KeyStroke.getKeyStroke(keyCode, modifiers, onKeyRelease);
            inputMap.put(keyStroke, keyStroke.toString());
            actionMap.put(keyStroke.toString(), this);
            for(JComponent jc : components) {
                inputMap = jc.getInputMap(condition);
                actionMap = jc.getActionMap();
                keyStroke = KeyStroke.getKeyStroke(keyCode, modifiers, onKeyRelease);
                inputMap.put(keyStroke, keyStroke.toString());
                actionMap.put(keyStroke.toString(), this);
            }
        }

    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        if(up)
            y -= 1;
        if(down)
            y += 1;
        if(right)
            x += 1;
        if(left)
            x -= 1;
        if(x < 0)
            x = 0;
        else if(x > frame.getWidth() - 30)
            x = frame.getWidth() - 30;
        if(y < 0)
            y = 0;
        else if(y > frame.getHeight() - 50)
            y = frame.getHeight() - 50;
        g.drawRect(x, y, 30, 30);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        frame.repaint();
    }

}

1 个答案:

答案 0 :(得分:2)

  

我正在使用KeyBindings,并且使用的条件为WHEN_IN_FOCUSED_WINDOW

有3个InputMap:

  1. JComponent.WHEN_FOCUSED
  2. JComponent。WHEN_ANCESTOR_OF_FOCUSED_
  3. JComponent.WHEN_IN_FOCUSED_WINDOW

WHEN_FOCUSED具有优先权,因此您不能仅将键绑定添加到父面板。

因此,您可以:

  1. 也将绑定添加到文本字段或
  2. 从文本字段中删除绑定。

请参见How to Remove Key Bindings

编辑:

看看UIManager Defaults。它将显示每个组件的默认属性,包括该组件使用哪些InputMap。

因此对于JTextField,您可以使用以下命令删除所有文本字段的默认绑定:

InputMap im = (InputMap)UIManager.get("TextField.focusInputMap");
KeyStroke keyStroke = KeyStroke.getKeyStroke("RIGHT");
im.put(keyStroke, "none"); //noop

以上内容将禁用所有文本字段的向右箭头键。然后,我相信文本字段父面板的绑定现在将变为活动状态。

如果没有,您可以尝试更改文本字段的默认操作。看一下Key Bindings。它将显示每个组件的默认绑定。因此,您只需将Action替换为特定的绑定即可。  像这样:

ActionMap am = (ActionMap)UIManager.get("TextField.actionMap");
am.put("caret-forward", yourRightActionHere);

如果只想更改某些文本字段,则需要从每个文本字段组件中获取InputMap或ActionMap。