【问题标题】:Java Swing: consuming key eventsJava Swing:消费关键事件
【发布时间】:2014-12-23 19:14:13
【问题描述】:

我有一个 JFrame(包含各种文本字段和表格等),并且想要安装一个热键功能,该功能在框架打开时应用(有点像菜单加速器快捷方式)。以下主要有效,无论哪个字段或控件具有焦点,都会调用我的操作:

String MY_GLOBAL_ACTION_TRIGGER = "hotKey";
InputMap im = getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
KeyStroke ks = KeyStroke.getKeyStroke('`');
im.put(ks, MY_GLOBAL_ACTION_TRIGGER);
ActionMap am = getRootPane().getActionMap();
am.put(MY_ACTION_TRIGGER, new AbstractAction() { public void actionPerformed() ... });

但是,按键没有被消耗,我仍然在文本字段中插入了一个反引号。调用我的操作后,如何防止按键传播到文本字段?

【问题讨论】:

    标签: java swing


    【解决方案1】:

    使用 KeyboardFocusManager 和 KeyEventDispatcher

    private void myListener implements KeyEventDispatcher {
      public boolean dispatchKeyEvent (KeyEvent ke) {
        if (ke.getKeyChar() == '`') {
          MY_GLOBAL_ACTION.actionPerformed(null);
          return true;
        }
        return false;
      }
    }
    

    【讨论】:

    • 请注意,这不会捕获用户将文本粘贴到字段中的用例...
    • 1+ 用于处理热键。如果 KeyEvent 没有被分派,那么您不必担心它会被分派给其他组件。
    【解决方案2】:

    文本字段可能优先于键事件通知,这意味着您的键绑定直到文本字段更新后才会收到通知

    一般来说,您确实不想监控文本组件上的击键/事件,因为它没有考虑用户将文本粘贴到字段中的用例

    如果你想过滤进入 textField 的内容,你应该使用DocumentFilter

    Implementing a DocumentFilter

    【讨论】:

    • 我对监视单个文本组件上的事件不感兴趣,我试图将窗口上的关键事件作为一个整体来处理(有点像菜单加速器快捷键)。
    • 您对什么感兴趣以及您可以实现什么是不同的问题。通常,文本组件在键绑定和其他键侦听器之前处理键事件。 DocumentFilter 在将内容提交到Document 之前对其进行处理,包括用户将文本粘贴到字段中的用例。消费事件也可能不够,因为一些关键进程也可以忽略消费状态。你需要决定什么是有效的......
    【解决方案3】:

    这里有两个问题:

  • char 参数构造的KeyStroke 似乎并没有真正捕捉到中风。尝试使用KeyStroke(KeyEvent key, int modifiers)
  • 文本字段应该过滤选定的笔画,或者更确切地说,听众应该使用它们。

    尝试类似:

    public class KeyStrokeFrame extends JFrame {
        public static void main(String[] args) {
            new KeyStrokeFrame().setVisible(true);
        }
    
        public KeyStrokeFrame() {
            setSize(200, 200);
            JTextField jtf = new JTextField();
            getContentPane().add(jtf);
            String MY_GLOBAL_ACTION_TRIGGER = "hotKey";
            InputMap im = getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
            KeyStroke ks = KeyStroke.getKeyStroke(KeyEvent.VK_1, 0);
            ((AbstractDocument)jtf.getDocument()).setDocumentFilter(new DocumentFilter() {
                @Override
                public void insertString(FilterBypass fb, int offset,
                        String string, AttributeSet attr)
                        throws BadLocationException {
                    if (string.equals("1")) return;
                    super.insertString(fb, offset, string, attr);
                }
    
                @Override
                public void replace(FilterBypass fb, int offset, int length,
                        String text, AttributeSet attrs)
                        throws BadLocationException {
                    if (text.equals("1")) return;
                    super.replace(fb, offset, length, text, attrs);
                }
            });
            im.put(ks, MY_GLOBAL_ACTION_TRIGGER);
            ActionMap am = getRootPane().getActionMap();
            am.put(MY_GLOBAL_ACTION_TRIGGER, new AbstractAction() { 
                public void actionPerformed(ActionEvent e) {
                    System.out.println("pressed");} 
                }); 
            }
    }
    
  • 【讨论】:

    • 抱歉,我的代码不是很清楚,我没有在动作映射中添加动作处理程序。我现在更新了代码。谢谢你。
    猜你喜欢
    • 2014-03-30
    • 2012-02-08
    • 2019-01-01
    • 2017-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-06
    • 1970-01-01
    相关资源
    最近更新 更多