JFrame的KeyListener无响应


80

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

有什么我想念的吗?

Answers:


51

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

过程是一样的:

myComponent.addKeyListener(new KeyListener ...);

注意:某些组件无法像JLabel那样聚焦。

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

myComponent.setFocusable(true);

2
是的,您是对的,在程序启动时,您可以稍微看到焦点在按钮A上。向每个按钮添加一个按键监听器可以解决此问题。有点奇怪,我认为向JFrame添加keylistener会起作用,但我想不会。谢谢!
Tomek

我在JFrame上做了一个监听器,可以从键盘监听。我想让它在被动模式下工作,即使窗口不在前面(聚焦)。JFrame不在被动模式下侦听。
乌斯曼2015年

132

如果您不想在每个组件上注册一个侦听器,则
可以将自己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);
    }
}

5
KeyboardFocusManager适用于整个应用程序,如果您有多个框架,会遇到麻烦吗?
neoedmund

2
因此,这应该可以正常工作,例如:foreach(“框架中的可聚焦组件”为_){_.addkeylistener(frameKeylistener);}
neoedmund

16

InputMap和ActionMap旨在捕获组件,组件及其所有子组件或整个窗口的键事件。这是通过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);

10

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

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

有关应执行的操作的详细信息,请参见我关于应用程序级键盘快捷键-Java Swing的答复。


10

我遇到了同样的问题,直到我读到真正的问题是关于FOCUS的问题,您的JFrame已经添加了侦听器,但是巡视框架从来没有放在Focus上,因为您在JFrame中拥有很多可以聚焦的组件,所以请尝试:

JFrame.setFocusable(true);

祝好运


2
我发现这只有在我使用JFrame上的东西然后KeyListener不再响应之前
才起作用

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;
}

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;
    }
}

对于一个可行的示例,您可以考虑添加导入。我通常会添加“包导入”以使其简短。否则,+ 1。有趣的技术。
Andrew Thompson

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);
    }
}

我也得到了所有消息输出。在Windows命令行中运行。
Darrel

2
您会收到所有消息,因为在此示例中,JFrame具有焦点。尝试将TextBox组件添加到JFrame,然后看看会发生什么。
bruno conde

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");
        }
    });

1

我一直有同样的问题。我听了Bruno的建议,发现仅在JFrame中的“第一个”按钮(即,左上角)上添加KeyListener就可以了。但是我同意你的看法,这是一个令人不安的解决方案。于是我四处弄弄,发现了一种更整洁的方法来修复它。只需添加行

myChildOfJFrame.requestFocusInWindow();

创建主JFrame子类的实例并将其设置为可见后,将其转换为主要方法。


谢谢,有同样的问题。奇怪的是,即使它是内容窗格,该组件也会失去焦点……
Androbin '16

-3

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

addKeyListener(this);

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


8
您应该真正解释“正确的位置”以使它成为有用的答案。
直到2012年

-3

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

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

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


4
-1绝对不是-从多个方面来说都是完整的<strong censored>:a)不雅的子类化b)不雅的引用通过c)绘画时状态不正确d)..
kleopatra 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.