JPanel 上的 KeyListener 随机无响应

发布于 2024-12-15 10:07:17 字数 1695 浏览 0 评论 0原文

我的项目中的默认 Java KeyListener 遇到问题。 我注意到,当我启动时,KeyListener 有时似乎没有转发 KeyEvents。

问题的症状: 启动应用程序时,不处理按键输入。这只是有时发生。有时我必须关闭并启动应用程序 7-8 次,直到出现此情况。有时这是第一次尝试。当发生这种情况时,除非我再次重新启动应用程序,否则它将无法工作。

我正在使用的: Window 7 x64 以及最新的 Eclipse 和 JDK 版本。

我已经发现的内容: 我已在调试模式下设置断点并检查 JPanel 实例。看来 KeyListener 总是成功添加到其中。 此外,MouseListener 和 MouseMotionListener 始终工作得很好。

最少的代码:

public class Player implements KeyListener
{
    public void keyTyped(KeyEvent e){}
    public void keyReleased(KeyEvent e){ }

    public void keyPressed(KeyEvent e){
        System.out.println("Key Pressed!");
    }

}

public class Game {

    public static void main(String[] args) {
        new Game();
    } 

    public Game(){
        JFrame window = new JFrame();
        window.setVisible(true);

        //Now set the window size correctly
        window.setSize(800, 600);  
        //Set-up the rest of the window
        window.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        window.setResizable(true);


        //Create our panel
        JPanel canvas = new JPanel();
        canvas.setFocusable(true);
        window.add( canvas ); //Add it to our window

        Player k = new Player();
        canvas.addKeyListener(k);
    }
}

感谢您的宝贵时间!

附: 好吧,回答我自己的问题:

似乎我必须在设置窗口大小之后调用 setVisible(true) :

    JFrame window = new JFrame();


    Now set the window size correctly
    window.setSize(800, 600);  
    window.setVisible(true);

像这样切换 setSize() 和 setVisible() 似乎可以使其工作。试了大概十几次都没有问题。

我猜想如果窗口大小为 0x0,setVisible 可能不喜欢将焦点赋予窗口。 问题是:为什么这只会在某些情况下导致问题?

I'm having trouble with the default Java KeyListener in my project.
I noticed that the KeyListener doesn't seem to get KeyEvents forwarded sometimes when I start.

Symptoms of the problem:
When starting the application key input isn't processed. This only happens sometimes. Sometimes I have to close and start the app 7-8 times until this shows up. Sometimes it's the first try. When it happens it won't work until I restart the app again.

What I'm using:
Window 7 x64 and the newest Eclipse and JDK versions.

What I found out already:
I've put a breakpoint in debug mode and checked the JPanel instance out. The KeyListener is always successfully added to it, it seems.
Also, MouseListener and MouseMotionListener work just fine, all the time.

Minimal code:

public class Player implements KeyListener
{
    public void keyTyped(KeyEvent e){}
    public void keyReleased(KeyEvent e){ }

    public void keyPressed(KeyEvent e){
        System.out.println("Key Pressed!");
    }

}

public class Game {

    public static void main(String[] args) {
        new Game();
    } 

    public Game(){
        JFrame window = new JFrame();
        window.setVisible(true);

        //Now set the window size correctly
        window.setSize(800, 600);  
        //Set-up the rest of the window
        window.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        window.setResizable(true);


        //Create our panel
        JPanel canvas = new JPanel();
        canvas.setFocusable(true);
        window.add( canvas ); //Add it to our window

        Player k = new Player();
        canvas.addKeyListener(k);
    }
}

Thank you for your time!

PS:
Ok, answer to my own question:

It seems that I have to call setVisible(true) after setting the window's size:

    JFrame window = new JFrame();


    Now set the window size correctly
    window.setSize(800, 600);  
    window.setVisible(true);

Switching out the setSize() and setVisible() like this seems to make it work. Tried it about a dozen times without a problem.

I guess setVisible might not like giving Focus to the window if it's of size 0x0.
The question is: Why does this only cause a problem in one out of some cases?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

我要还你自由 2024-12-22 10:07:17

尝试将 JButton 添加到您的“画布”JPanel,然后按下该按钮并查看您的 KeyListener 发生什么情况 - 它会失败,因为 JPanel 失去了焦点。为了防止这种情况发生,请改用按键绑定(请参阅上面我的评论中的教程链接)。例如,

import java.awt.event.*;
import java.awt.*;
import javax.swing.*;

@SuppressWarnings("serial")
public class Game2 {

   private static final String UP = "up";

   public static void main(String[] args) {
      new Game2();
   }

   public Game2() {
      JFrame window = new JFrame("Press up-arrow key");
      window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

      JPanel canvas = new JPanel();
      canvas.setPreferredSize(new Dimension(400, 300));
      window.add(canvas);

      canvas.add(new JButton(new AbstractAction("Press space-bar") {
         public void actionPerformed(ActionEvent e) {
            System.out.println("Button or space-bar pressed");
         }
      }));
      ActionMap actionMap = canvas.getActionMap();
      int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
      InputMap inputMap = canvas.getInputMap(condition);

      inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), UP);
      actionMap.put(UP, new UpAction());

      window.pack();
      window.setLocationRelativeTo(null);
      window.setVisible(true);
   }
}

@SuppressWarnings("serial")
class UpAction extends AbstractAction {
   @Override
   public void actionPerformed(ActionEvent arg0) {
      System.out.println("Up Arrow pressed!");
   }
}

Try adding a JButton to your "canvas" JPanel, then pressing the button and seeing what happens to your KeyListener -- it fails because the JPanel lost the focus. To prevent this from happening, use Key Bindings instead (see the link in my comment above for the tutorial). For e.g.,

import java.awt.event.*;
import java.awt.*;
import javax.swing.*;

@SuppressWarnings("serial")
public class Game2 {

   private static final String UP = "up";

   public static void main(String[] args) {
      new Game2();
   }

   public Game2() {
      JFrame window = new JFrame("Press up-arrow key");
      window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

      JPanel canvas = new JPanel();
      canvas.setPreferredSize(new Dimension(400, 300));
      window.add(canvas);

      canvas.add(new JButton(new AbstractAction("Press space-bar") {
         public void actionPerformed(ActionEvent e) {
            System.out.println("Button or space-bar pressed");
         }
      }));
      ActionMap actionMap = canvas.getActionMap();
      int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
      InputMap inputMap = canvas.getInputMap(condition);

      inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), UP);
      actionMap.put(UP, new UpAction());

      window.pack();
      window.setLocationRelativeTo(null);
      window.setVisible(true);
   }
}

@SuppressWarnings("serial")
class UpAction extends AbstractAction {
   @Override
   public void actionPerformed(ActionEvent arg0) {
      System.out.println("Up Arrow pressed!");
   }
}
森末i 2024-12-22 10:07:17

不知道这是否与您的问题有关,但由于它的间歇性,也许是......您应该最后在 Swing 线程中执行 setVisible() 。如果需要,您可以在 setVisible 之后调用 setSize,但用户可能会看到闪烁,同样应该在 swing 线程中完成。将此作为最后一步:

SwingUtilities.invokeLater( new Runnable() {
   public void run() {
      window.setVisible( true );
   }
} );

为此,您还需要将窗口声明定为最终的:

...
final JFrame window = new JFrame();
...

Don't know if this is related to your problems, but due to the intermittent nature of it perhaps it is...You should execute setVisible() last and in the swing thread. You could call setSize after setVisible if you want to, but the user might see a flicker and it likewise should be done in the swing thread. Do this as your last step:

SwingUtilities.invokeLater( new Runnable() {
   public void run() {
      window.setVisible( true );
   }
} );

To do this, you will also need to make window declaration final:

...
final JFrame window = new JFrame();
...
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文