Java KeyBindings生效数秒后失效问题求助
解决KeyBindings生效数秒后失效的问题
我帮你找到了问题所在!你的KeyBindings失效的核心原因是输入映射的焦点依赖,结合你的代码,咱们一步步修复:
问题根源
你当前调用p.getInputMap()时,默认使用的是JComponent.WHEN_FOCUSED模式——这意味着只有当JPanelp获得焦点时,按键绑定才会触发。虽然你在初始化时调用了p.requestFocusInWindow(),但程序运行中焦点很容易意外转移(比如点击窗口空白区域、其他组件抢焦点),一旦JPanel失去焦点,所有按键绑定就会完全失效。
你提到尝试过WHEN_IN_FOCUSED_WINDOW但没效果,应该是调用方式不对,需要明确指定这个参数来获取对应的输入映射。
修复步骤
1. 修改输入映射的获取方式
在setupKeyBindings方法中,所有p.getInputMap()都要替换为p.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW),这样按键绑定会绑定到窗口级别,只要窗口处于激活状态,不管哪个组件获得焦点,按键都会触发。
2. 移除不必要的焦点相关代码
既然用了窗口级别的输入映射,就不需要再依赖JPanel的焦点了,移除以下两行代码:
p.setFocusable(true); p.requestFocusInWindow();
修改后的完整代码
import java.awt.Color; import java.awt.EventQueue; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.KeyStroke; import javax.swing.Timer; public class KeyBindingTest extends JFrame implements ActionListener { long counter = 0; int speed = 5; boolean isUp = false, isDown = false, isLeft = false, isRight = false; JLabel j = new JLabel(); JPanel p = new JPanel(); Timer t; Action upPressed = new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { System.out.println("up on"); isUp = true; } }; Action upReleased = new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { isUp = false; System.out.println("up off"); } }; Action downPressed = new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { System.out.println("down on"); isDown = true; } }; Action downReleased = new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { isDown = false; System.out.println("down off"); } }; Action leftPressed = new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { System.out.println("left on"); isLeft = true; } }; Action leftReleased = new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { isLeft = false; System.out.println("left off"); } }; Action rightPressed = new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { System.out.println("right on"); isRight = true; } }; Action rightReleased = new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { isRight = false; System.out.println("right off"); } }; public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { try { KeyBindingTest window = new KeyBindingTest(); window.run(); } catch (Exception e) { e.printStackTrace(); } } }); } private void run() { this.setBounds(640, 400, 640, 400); this.setVisible(true); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); p.setBounds(0, 0, this.getWidth(), this.getHeight()); p.setVisible(true); p.setBackground(Color.blue); p.setOpaque(true); p.setLayout(null); j.setBounds(320, 200, 10, 10); j.setVisible(true); j.setBackground(Color.red); j.setOpaque(true); this.add(p); p.add(j); setupKeyBindings(); t = new Timer(1000 / 40, this); t.start(); } private void setupKeyBindings() { // 明确使用窗口级别的输入映射 p.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("W"), "moveUp"); p.getActionMap().put("moveUp", upPressed); p.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released W"), "stopUp"); p.getActionMap().put("stopUp", upReleased); p.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("S"), "moveDown"); p.getActionMap().put("moveDown", downPressed); p.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released S"), "stopDown"); p.getActionMap().put("stopDown", downReleased); p.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("A"), "moveLeft"); p.getActionMap().put("moveLeft", leftPressed); p.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released A"), "stopLeft"); p.getActionMap().put("stopLeft", leftReleased); p.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("D"), "moveRight"); p.getActionMap().put("moveRight", rightPressed); p.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released D"), "stopRight"); p.getActionMap().put("stopRight", rightReleased); } @Override public void actionPerformed(ActionEvent e) { counter++; System.out.println(counter); if (isUp) { j.setLocation(j.getX(), j.getY() - speed); } if (isDown) { j.setLocation(j.getX(), j.getY() + speed); } if (isLeft) { j.setLocation(j.getX() - speed, j.getY()); } if (isRight) { j.setLocation(j.getX() + speed, j.getY()); } repaint(); } }
额外优化建议
你可以把重复的按键绑定逻辑抽成一个工具方法,减少代码冗余,比如:
private void bindKey(String key, String pressedActionKey, Action pressedAction, String releasedActionKey, Action releasedAction) { p.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(key), pressedActionKey); p.getActionMap().put(pressedActionKey, pressedAction); p.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released " + key), releasedActionKey); p.getActionMap().put(releasedActionKey, releasedAction); }
然后在setupKeyBindings里直接调用:
bindKey("W", "moveUp", upPressed, "stopUp", upReleased); bindKey("S", "moveDown", downPressed, "stopDown", downReleased); // ... 其他方向键同理
内容的提问来源于stack exchange,提问作者iopener
相关产品推荐
相关产品推荐

