【问题标题】:Unresponsive KeyListener for JFrameJFrame 的无响应 KeyListener
【发布时间】:2010-09-22 03:38:36
【问题描述】:

我正在尝试为我的JFrame 实现一个KeyListener。在构造函数上,我正在使用以下代码:

System.out.println("test");
addKeyListener(new KeyListener() {
    public void keyPressed(KeyEvent e) { System.out.println( "tester"); }

    public void keyReleased(KeyEvent e) { System.out.println("2test2"); }

    public void keyTyped(KeyEvent e) { System.out.println("3test3"); }
});

当我运行它时,test 消息出现在我的控制台中。但是,当我按下一个键时,我没有收到任何其他消息,好像KeyListener 甚至都不存在。

我在想这可能是因为焦点不在JFrame
所以他们KeyListener 没有收到任何事件。但是,我很确定它是。

我有什么遗漏的吗?

【问题讨论】:

    标签: java swing jframe keylistener


    【解决方案1】:

    嗯......你的构造函数是什么类?可能是一些扩展 JFrame 的类?当然,窗口焦点应该在窗口上,但我认为这不是问题。

    我扩展了您的代码,尝试运行它并且它工作 - 按键导致打印输出。 (通过 Eclipse 与 Ubuntu 一起运行):

    public class MyFrame extends JFrame {
        public MyFrame() {
            System.out.println("test");
            addKeyListener(new KeyListener() {
                public void keyPressed(KeyEvent e) {
                    System.out.println("tester");
                }
    
                public void keyReleased(KeyEvent e) {
                    System.out.println("2test2");
                }
    
                public void keyTyped(KeyEvent e) {
                    System.out.println("3test3");
                }
            });
        }
    
        public static void main(String[] args) {
            MyFrame f = new MyFrame();
            f.pack();
            f.setVisible(true);
        }
    }
    

    【讨论】:

    • 我也得到了所有的消息输出。在 Windows 命令行中运行。
    • 您会收到所有消息,因为在此示例中 JFrame 具有焦点。尝试向 JFrame 添加一个 TextBox 组件,看看会发生什么。
    【解决方案2】:

    您必须将您的 keyListener 添加到您需要的每个组件中。只有具有焦点的组件才会发送这些事件。例如,如果您的 JFrame 中只有一个 TextBox,则该 TextBox 具有焦点。所以你也必须给这个组件添加一个 KeyListener。

    过程相同:

    myComponent.addKeyListener(new KeyListener ...);
    

    注意:有些组件不像 JLabel 那样可聚焦。

    要将它们设置为可聚焦,您需要:

    myComponent.setFocusable(true);
    

    【讨论】:

    • 是的,你是对的,当程序启动时,你可以稍微看到焦点在按钮 A 上。为每个按钮添加一个 keylistener 解决了这个问题。这有点奇怪,我认为向 JFrame 添加一个 keylistener 会起作用,但我想不是。谢谢!
    • 我在 JFrame 上创建了一个监听器,它从键盘监听。我想让它在被动模式下工作,即使窗口不在前面(聚焦)。 JFrame 没有在被动模式下监听。
    【解决方案3】:

    KeyListener 是低级别的,仅适用于单个组件。尽管尝试使其更可用JFrame 创建了许多组件组件,最明显的是内容窗格。 JComboBox UI 也经常以类似的方式实现。

    值得注意的是,鼠标事件的工作方式与按键事件略有不同。

    有关您应该做什么的详细信息,请参阅我在 Application wide keyboard shortcut - Java Swing 上的回答。

    【讨论】:

      【解决方案4】:

      我遇到了同样的问题,直到我读到真正的问题是关于 FOCUS 的,你的 JFrame 已经添加了侦听器,但是游览框架永远不会在焦点上,因为你的 JFrame 中有很多组件也是可聚焦的,所以试试:

      JFrame.setFocusable(true);
      

      祝你好运

      【讨论】:

      • 我发现这只有在我使用 JFrame 上的某些东西时才有效,然后 KeyListener 不再响应
      【解决方案5】:

      如果您不想在每个组件上都注册一个监听器,
      你可以将你自己的KeyEventDispatcher添加到KeyboardFocusManager

      public class MyFrame extends JFrame {    
          private class MyDispatcher implements KeyEventDispatcher {
              @Override
              public boolean dispatchKeyEvent(KeyEvent e) {
                  if (e.getID() == KeyEvent.KEY_PRESSED) {
                      System.out.println("tester");
                  } else if (e.getID() == KeyEvent.KEY_RELEASED) {
                      System.out.println("2test2");
                  } else if (e.getID() == KeyEvent.KEY_TYPED) {
                      System.out.println("3test3");
                  }
                  return false;
              }
          }
          public MyFrame() {
              add(new JTextField());
              System.out.println("test");
              KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
              manager.addKeyEventDispatcher(new MyDispatcher());
          }
      
          public static void main(String[] args) {
              MyFrame f = new MyFrame();
              f.pack();
              f.setVisible(true);
          }
      }
      

      【讨论】:

      • KeyboardFocusManager 是应用程序范围的,如果你有多个框架,你会遇到麻烦吗?
      • 所以这应该可以工作,例如:foreach("frameable components in the frame" as _){ _.addkeylistener(frameKeylistener);}
      【解决方案6】:

      我也遇到了同样的问题。我听从 Bruno 给您的建议,发现将 KeyListener 添加到 JFrame 中的“第一个”按钮(即左上角)就可以了。但我同意你的看法,这是一种令人不安的解决方案。所以我摆弄了一下,发现了一种更巧妙的方法来修复它。只需添加一行

      myChildOfJFrame.requestFocusInWindow();
      

      在您创建 JFrame 子类的实例并将其设置为可见之后,添加到您的 main 方法。

      【讨论】:

      • 谢谢,遇到了同样的问题。奇怪的是,即使它是内容窗格,组件也会失去焦点......
      【解决方案7】:

      Deion(以及任何其他提出类似问题的人),您可以使用上面 Peter 的代码,但不是打印到标准输出,而是测试关键代码 PRESSED、RELEASED 或 TYPED。

      @Override
      public boolean dispatchKeyEvent(KeyEvent e) {
          if (e.getID() == KeyEvent.KEY_PRESSED) {
              if (e.getKeyCode() == KeyEvent.VK_F4) {
                  dispose();
              }
          } else if (e.getID() == KeyEvent.KEY_RELEASED) {
              if (e.getKeyCode() == KeyEvent.VK_F4) {
                  dispose();
              }
          } else if (e.getID() == KeyEvent.KEY_TYPED) {
              if (e.getKeyCode() == KeyEvent.VK_F4) {
                  dispose();
              }
          }
          return false;
      }
      

      【讨论】:

        【解决方案8】:

        为了捕获JFrame中所有文本字段的关键事件, 可以使用关键事件后处理器。 这是一个工作示例,在您添加明显的包含之后。

        public class KeyListenerF1Demo extends JFrame implements KeyEventPostProcessor {
            public static final long serialVersionUID = 1L;
        
            public KeyListenerF1Demo() {
                setTitle(getClass().getName());
        
                // Define two labels and two text fields all in a row.
                setLayout(new FlowLayout());
        
                JLabel label1 = new JLabel("Text1");
                label1.setName("Label1");
                add(label1);
        
                JTextField text1 = new JTextField(10);
                text1.setName("Text1");
                add(text1);
        
                JLabel label2 = new JLabel("Text2");
                label2.setName("Label2");
                add(label2);
        
                JTextField text2 = new JTextField(10);
                text2.setName("Text2");
                add(text2);
        
                // Register a key event post processor.
                KeyboardFocusManager.getCurrentKeyboardFocusManager()
                        .addKeyEventPostProcessor(this);
            }
        
            public static void main(String[] args) {
                JFrame f = new KeyListenerF1Demo();
                f.setName("MyFrame");
                f.pack();
                f.setVisible(true);
            }
        
            @Override
            public boolean postProcessKeyEvent(KeyEvent ke) {
                // Check for function key F1 pressed.
                if (ke.getID() == KeyEvent.KEY_PRESSED
                        && ke.getKeyCode() == KeyEvent.VK_F1) {
        
                    // Get top level ancestor of focused element.
                    Component c = ke.getComponent();
                    while (null != c.getParent())
                        c = c.getParent();
        
                    // Output some help.
                    System.out.println("Help for " + c.getName() + "."
                            + ke.getComponent().getName());
        
                    // Tell keyboard focus manager that event has been fully handled.
                    return true;
                }
        
                // Let keyboard focus manager handle the event further.
                return false;
            }
        }
        

        【讨论】:

        • 对于一个工作示例,您可以考虑添加导入。我通常会添加“包导入”以保持简短。否则,+1。有趣的技术。
        【解决方案9】:

        lol .... 你所要做的就是确保

        addKeyListener(this);

        已正确放置在您的代码中。

        【讨论】:

        • 您应该真正解释“正确的地方”,以使其成为一个有用的答案。
        【解决方案10】:

        您可以让自定义 JComponent 将其父 JFrame 设置为可聚焦。

        只需添加一个构造函数并传入 JFrame。然后调用paintComponent中的setFocusable()。

        这样 JFrame 将始终接收 KeyEvents 而不管其他组件是否被按下。

        【讨论】:

        • -1 绝对不是 - 这在多个方面都是完整的:a)不雅的子类化 b)不雅的引用传递 c)绘画时不适当的状态变化 d)..
        【解决方案11】:

        InputMaps 和 ActionMaps 旨在捕获组件、组件及其所有子组件或整个窗口的关键事件。这是通过 JComponent.getInputMap() 中的参数控制的。有关文档,请参阅 How to Use Key Bindings

        这种设计的美妙之处在于,人们可以挑选哪些按键对监控很重要,并根据这些按键触发不同的操作。

        当在窗口中的任意位置按下转义键时,此代码将在 JFrame 上调用 dispose()。 JFrame 不是从 JComponent 派生的,因此您必须使用 JFrame 中的另一个组件来创建键绑定。内容窗格可能就是这样一个组件。

        InputMap inputMap; 
        ActionMap actionMap;
        AbstractAction action;
        JComponent component;
        
        inputMap  = component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
        actionMap = component.getActionMap();
        
        action    = new AbstractAction()
        {
           @Override
           public void actionPerformed(ActionEvent e)
           {
              dispose();
           }
        };
        
        inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "dispose");
        actionMap.put("dispose", action);
        

        【讨论】:

          【解决方案12】:

          这应该会有所帮助

              yourJFrame.setFocusable(true);
              yourJFrame.addKeyListener(new java.awt.event.KeyAdapter() {
          
          
                  @Override
                  public void keyTyped(KeyEvent e) {
                      System.out.println("you typed a key");
                  }
          
                  @Override
                  public void keyPressed(KeyEvent e) {
                      System.out.println("you pressed a key");
                  }
          
                  @Override
                  public void keyReleased(KeyEvent e) {
                      System.out.println("you released a key");
                  }
              });
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-07-24
            • 2011-12-26
            • 1970-01-01
            • 2014-06-04
            • 2013-03-05
            相关资源
            最近更新 更多