简体   繁体   English

JFrame的KeyListener没有响应

[英]Unresponsive KeyListener for JFrame

I'm trying to implement a KeyListener for my JFrame . 我正在尝试为JFrame实现KeyListener On the constructor, I'm using this code: 在构造函数上,我使用以下代码:

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

When I run it, the test message comes up in my console. 当我运行它时, test消息会出现在我的控制台中。 However, when I press a key, I don't get any of the other messages, as if the KeyListener was not even there. 但是,当我按一个键时,没有收到其他任何消息,就好像KeyListener不在那儿一样。

I was thinking that it could be because the focus is not on the JFrame 我在想这可能是因为重点不在JFrame
and so they KeyListener doesn't receive any events. 因此,它们的KeyListener不会收到任何事件。 But, I'm pretty sure it is. 但是,我很确定。

Is there something that I am missing? 有什么我想念的吗?

If you don't want to register a listener on every component, 如果您不想在每个组件上注册一个侦听器,
you could add your own KeyEventDispatcher to the KeyboardFocusManager : 您可以将自己的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);
    }
}

You must add your keyListener to every component that you need. 您必须将keyListener添加到所需的每个组件中。 Only the component with the focus will send these events. 仅具有焦点的组件将发送这些事件。 For instance, if you have only one TextBox in your JFrame, that TextBox has the focus. 例如,如果JFrame中只有一个TextBox,则该TextBox具有焦点。 So you must add a KeyListener to this component as well. 因此,您还必须将KeyListener添加到此组件。

The process is the same: 过程是一样的:

myComponent.addKeyListener(new KeyListener ...);

Note: Some components aren't focusable like JLabel. 注意:某些组件无法像JLabel那样聚焦。

For setting them to focusable you need to: 要将它们设置为可聚焦,您需要:

myComponent.setFocusable(true);

InputMaps and ActionMaps were designed to capture the key events for the component, it and all of its sub-components, or the entire window. InputMap和ActionMap旨在捕获组件,组件及其所有子组件或整个窗口的键事件。 This is controlled through the parameter in JComponent.getInputMap(). 这是通过JComponent.getInputMap()中的参数控制的。 See How to Use Key Bindings for documentation. 有关文档,请参见如何使用键绑定

The beauty of this design is that one can pick and choose which key strokes are important to monitor and have different actions fired based on those key strokes. 此设计的优点在于,可以选择并选择哪些按键对于监视非常重要,并根据这些按键触发不同的动作。

This code will call dispose() on a JFrame when the escape key is hit anywhere in the window. 当在窗口中的任意位置按下转义键时,此代码将在JFrame上调用dispose()。 JFrame doesn't derive from JComponent so you have to use another component in the JFrame to create the key binding. JFrame不是从JComponent派生的,因此您必须使用JFrame中的另一个组件来创建键绑定。 The content pane might be such a component. 内容窗格可能就是这样的组件。

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

KeyListener is low level and applies only to a single component. KeyListener是低级别的,仅适用于单个组件。 Despite attempts to make it more usable JFrame creates a number of component components, the most obvious being the content pane. 尽管试图使它变得更有用,但JFrame创建了许多组件组件,最明显的是内容窗格。 JComboBox UI is also often implemented in a similar manner. JComboBox UI通常也以类似的方式实现。

It's worth noting the mouse events work in a strange way slightly different to key events. 值得注意的是,鼠标事件的工作方式与键事件略有不同。

For details on what you should do, see my answer on Application wide keyboard shortcut - Java Swing . 有关应执行的操作的详细信息,请参见我关于应用程序级键盘快捷键-Java Swing的答复。

I got the same problem until i read that the real problem is about FOCUS the your JFrame has already added Listeners but tour frame is never on Focus because you got a lot of components inside your JFrame that also are focusable so try: 我遇到了同样的问题,直到我读到真正的问题是关于FOCUS的问题为止,您的JFrame已经添加了侦听器,但是巡视框架从来没有放在Focus上,因为您在JFrame中拥有很多可以聚焦的组件,所以请尝试:

JFrame.setFocusable(true);

Good Luck 祝好运

Deion (and anyone else asking a similar question), you could use Peter's code above but instead of printing to standard output, you test for the key code PRESSED, RELEASED, or TYPED. 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;
}

in order to capture key events of ALL text fields in a JFrame , one can employ a key event post processor. 为了捕获JFrame中所有文本字段的键事件,可以使用一个键事件后处理器。 Here is a working example, after you add the obvious includes. 添加明显的包含之后,这是一个工作示例。

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

This should help 这应该有帮助

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

Hmm.. what class is your constructor for? 嗯..您的构造函数是什么类的? Probably some class extending JFrame? 可能是一些扩展JFrame的类? The window focus should be at the window, of course but I don't think that's the problem. 当然,窗口焦点应该在窗口上,但是我不认为这是问题所在。

I expanded your code, tried to run it and it worked - the key presses resulted as print output. 我扩展了您的代码,尝试运行它并成功了-按键结果作为打印输出。 (run with Ubuntu through Eclipse): (通过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);
    }
}

I have been having the same problem. 我一直有同样的问题。 I followed Bruno's advice to you and found that adding a KeyListener just to the "first" button in the JFrame (ie, on the top left) did the trick. 我听了Bruno的建议,发现仅在JFrame中的“第一个”按钮(即,左上方)上添加KeyListener就可以了。 But I agree with you it is kind of an unsettling solution. 但是我同意你的看法,这是一个令人不安的解决方案。 So I fiddled around and discovered a neater way to fix it. 所以我四处弄弄,发现了一种更整洁的方法来修复它。 Just add the line 只需添加行

myChildOfJFrame.requestFocusInWindow();

to your main method, after you've created your instance of your subclass of JFrame and set it visible. 创建主JFrame子类的实例并将其设置为可见后,将其转换为主要方法。

lol .... all you have to do is make sure that 大声笑..您要做的就是确保

addKeyListener(this); addKeyListener(this);

is placed correctly in your code. 已正确放置在您的代码中。

You could have custom JComponents set their parent JFrame focusable. 您可以让自定义JComponent将其父JFrame设置为可聚焦。

Just add a constructor and pass in the JFrame. 只需添加一个构造函数并传递JFrame。 Then make a call to setFocusable() in paintComponent. 然后在paintComponent中调用setFocusable()。

This way the JFrame will always receive KeyEvents regardless of whether other components are pressed. 这样,无论是否按下其他组件,JFrame都将始终接收KeyEvent。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM