82

我正在尝试KeyListener为我的JFrame. 在构造函数上,我正在使用以下代码:

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没有收到任何事件。但是,我很确定它是。

有什么我想念的吗?

4

12 回答 12

133

如果您不想在每个组件上注册一个侦听器,
您可以将自己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);
    }
}
于 2009-09-04T14:09:36.470 回答
52

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

过程是一样的:

myComponent.addKeyListener(new KeyListener ...);

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

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

myComponent.setFocusable(true);
于 2008-11-13T13:01:28.513 回答
16

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

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

当在窗口中的任何位置按下转义键时,此代码将在 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);
于 2013-02-23T00:29:07.607 回答
12

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

JFrame.setFocusable(true);

祝你好运

于 2009-04-27T15:30:43.683 回答
10

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

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

有关您应该做什么的详细信息,请参阅我对应用程序范围的键盘快捷键 - Java Swing的回答。

于 2008-11-13T13:18:58.853 回答
9

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;
}
于 2011-01-09T14:50:07.940 回答
4

为了捕获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;
    }
}
于 2011-07-15T19:47:38.677 回答
2

嗯..你的构造函数是什么类?可能是一些扩展 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);
    }
}
于 2008-11-13T10:39:13.753 回答
2

这应该有帮助

    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");
        }
    });
于 2014-06-27T15:20:24.503 回答
1

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

myChildOfJFrame.requestFocusInWindow();

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

于 2011-01-04T02:31:37.200 回答
-3

大声笑....您所要做的就是确保

addKeyListener(this);

正确放置在您的代码中。

于 2012-07-10T19:24:10.000 回答
-3

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

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

这样,无论是否按下其他组件,JFrame 都将始终接收 KeyEvents。

于 2012-11-09T20:22:18.297 回答