Keylistener 不适用于 JPanel

Posted

技术标签:

【中文标题】Keylistener 不适用于 JPanel【英文标题】:Keylistener not working for JPanel 【发布时间】:2013-05-08 00:02:40 【问题描述】:

当使用我的 JPanel 类中的 KeyListener 按下箭头键之一时,我正在尝试做某事。这是我的代码:

public class TestPanel extends JPanel implements KeyListener

    public TestPanel()
        this.addKeyListener(this);
        this.setFocusable(true);
        this.requestFocusInWindow();
    

    public void keyPressed(KeyEvent e) 
        if (e.getKeyCode() == KeyEvent.VK_RIGHT) 
            System.out.println("Right");

        

        if (e.getKeyCode() == KeyEvent.VK_LEFT) 
            System.out.println("Left");
        

    

    public void keyTyped(KeyEvent e) 
    public void keyReleased(KeyEvent e) 

我的 main 方法将此面板的新实例添加到框架并显示它。我需要将 keylistener 添加到 JFrame 吗?就我而言,这将是困难且效率低下的,所以如果可能的话,我想让它与这个 JPanel 一起工作。有谁知道我做错了什么?

编辑:键绑定代码也不起作用:

public class GamePanel extends JPanel implements ActionListener

//Constructor
public GamePanel()

    setupKeyBinding();
    this.setFocusable(true);
    this.requestFocusInWindow();




private void setupKeyBinding() 
    int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
    InputMap inMap = getInputMap(condition);
    ActionMap actMap = getActionMap();

    inMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "Left");
    actMap.put("Left", new leftAction());


private class leftAction extends AbstractAction 

       public void actionPerformed(ActionEvent e) 
          System.out.println("test");
       


public void actionPerformed(ActionEvent e) 
    //some other game info

 

谁能告诉我为什么这也不起作用? (我的第二个动作监听器用于我的游戏所需的其他东西)

【问题讨论】:

另一个想法可能是创建一个内部类并使用类似:“this.addKeyListener(inner class/anonymous inner class);” java keylistener not called的可能重复 【参考方案1】:

如果你搜索这个问题,你会看到它被问过并且已经被解决了很多次。

KeyListeners 需要在焦点组件上才能工作。一种解决方案是先使您的组件具有焦点,然后再使其成为焦点。 不过,最好还是使用键绑定。谷歌这方面的教程。

请查看我对this question 的回复以了解更多信息,包括许多血淋淋的细节。

【讨论】:

谢谢,我会研究键绑定,但是对于这个问题,我已经查看了各种解决方案,但看不出我在做什么不同。如何让我的组件获得焦点?我想我是通过使用 requestFocusInWindow() 焦点行为因平台而异;此外,如果有任何其他可聚焦的组件,KeyListener 在这方面将是脆弱的。 @user2373733 键绑定是要走的路。只需放下您的 KeyListener:它将为您节省一些时间并避免将来出现错误。 所以我阅读了 oracle 文档并查看了您的示例并尝试使用键绑定,但它没有工作,所以我去复制了您的键绑定代码并尝试了它,它仍然不起作用。目前不知道该怎么做 @user2373733:您必须创建并发布sscce。如果我们要帮助您解决此错误,您或我们必须隔离并识别错误,如果没有 sscce,我们很难做到这一点。【参考方案2】:

作为参考,我使用您的方法创建了一个示例;虽然它有效,但它也暗示了代码中其他地方的焦点问题。 Key Bindings 避免这种情况,如图here。

附录:这是我的工作键绑定。

private static class TestPanel extends JPanel 

    private static final String LEFT = "Left";
    private Action left = new AbstractAction(LEFT) 
        @Override
        public void actionPerformed(ActionEvent e) 
            System.out.println(LEFT);
        
    ;
    private static final String RIGHT = "Right";
    private Action right = new AbstractAction(RIGHT) 
        @Override
        public void actionPerformed(ActionEvent e) 
            System.out.println(RIGHT);
        
    ;

    public TestPanel() 
        this.getInputMap().put(
            KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), LEFT);
        this.getActionMap().put(LEFT, left);
        this.getInputMap().put(
            KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), RIGHT);
        this.getActionMap().put(RIGHT, right);
    

原始 SSCCE:

import java.awt.EventQueue;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JPanel;

/**
 * @see https://***.com/a/16531380/230513
 */
public class Test 

    private void display() 
        JFrame f = new JFrame("Test");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(new TestPanel());
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    

    private static class TestPanel extends JPanel implements KeyListener 

        public TestPanel() 

            this.addKeyListener(this);
            this.setFocusable(true);
            this.requestFocusInWindow();
        

        @Override
        public void keyPressed(KeyEvent e) 
            if (e.getKeyCode() == KeyEvent.VK_RIGHT) 
                System.out.println("Right");
            

            if (e.getKeyCode() == KeyEvent.VK_LEFT) 
                System.out.println("Left");
            
        

        @Override
        public void keyTyped(KeyEvent e) 
        

        @Override
        public void keyReleased(KeyEvent e) 
        
    

    public static void main(String[] args) 
        EventQueue.invokeLater(new Runnable() 
            @Override
            public void run() 
                new Test().display();
            
        );
    

【讨论】:

啊,谢谢,我不知道什么会引起关注。我在测试时将添加到框架中的所有其他面板设置为不可聚焦,以确保没有任何干扰。我现在正在尝试键绑定,虽然我对很多这些东西都不熟悉 我已将该代码添加到我的帖子中,如果有人能告诉我为什么这也不起作用,我将不胜感激! 我在上面添加了一个工作示例;如果您发布新问题,请告诉我们。 谢谢,在此之前我会做更多的研究。我问过我的老师关于我的问题以及其他很多人,但没有人能弄清楚。基本上它只有在我的面板有焦点时才有效。我认为这只适用于关键听众 缺少更多上下文,很难说;您尝试了三个输入映射中的每一个吗?【参考方案3】:

要在JPanel 上接收关键事件,您必须设置焦点:

setFocusable(true);
requestFocus(); 

JPanel 现在有了焦点,所以它接收关键事件

【讨论】:

【参考方案4】:

我必须做两件事:我添加了 comp.setFocusable(true);到监听关键事件的组件 comp,我添加了 comp.requestFocus();到导致 comp 失去焦点的每个动作。

【讨论】:

这在最好的情况下是一种黑客攻击,并且在窗口失去焦点或另一个窃取焦点的组件时很容易被破坏 - 正确的答案是使用键绑定 API

以上是关于Keylistener 不适用于 JPanel的主要内容,如果未能解决你的问题,请参考以下文章

用于 Enter 键的 Java 可编辑 JCombobox Keylistener 事件

Android 的 EditText 问题:KeyListener

KeyListener 多久检查一次键盘输入? (Java 图形用户界面)

按下回车键时文本字段中的 KeyListener 未触发

有没有办法在 Android 中检测德国元音变音

java keylistener 未调用