我在项目中使用默认的Java KeyListener遇到麻烦。
我注意到有时启动时,KeyListener似乎并没有转发KeyEvent。
问题症状:
启动应用程序时,未处理按键输入。这仅在有时发生。有时,我必须关闭并启动应用程序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);
}
}
感谢您的时间!
PS:
好吧,回答我自己的问题:
似乎我必须在设置窗口的大小后调用setVisible(true):
JFrame window = new JFrame();
Now set the window size correctly
window.setSize(800, 600);
window.setVisible(true);
像这样切换setSize()和setVisible()似乎可以使其工作。尝试了十几遍,没有问题。
我想如果setVisible的大小为0x0,可能不喜欢将Focus赋予窗口。
问题是:为什么这只会在某些情况下导致问题?
不要使用KeyListener,而要使用键绑定。 那么,专注并不是一件大事。
间歇性问题总是让我想起初始线程。
尝试将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!");
}
}
感谢您的示例代码。 我已经阅读了您的链接。 剩下的问题是为什么错误如此随机地发生。
不知道这是否与您的问题有关,但是由于它的间歇性,可能是...您应该在最后一个线程中执行setVisible()。 如果需要,可以在setVisible之后调用setSize,但是用户可能会看到闪烁,并且同样应该在swing线程中完成。 做这最后一步:
SwingUtilities.invokeLater( new Runnable() {
public void run() {
window.setVisible( true );
}
} );
为此,您还需要使窗口声明为final:
...
final JFrame window = new JFrame();
...
由于在第一个setSize()之后调用setVisible()解决了该问题,因此也应该可以。 我之所以没有将它称为最后一个是因为我想获取Frames Insets以获取标题栏/边框的大小。 这仅在您事先调用setVisible()时有效。