hacky 的解决方案是在 JPanel 上调用 requestFocusInWindow() 以确保它具有 KeyListener/KeyAdapter 的焦点,这应该只在添加 Componnet 之后调用(尽管要确保我的组件具有焦点我在通过revalidate() 和repaint() 刷新JFrame 之后调用它)例如:
public class MyUI {
//will switch to the gamepanel by removing all components from the frame and adding GamePanel
public void switchToGamePanel() {
frame.getContentPane().removeAll();
GamePanel gp = new GamePanel();//keylistener/keyadapter was added to Jpanel here
frame.add(gp);//add component. we could call requestFocusInWindow() after this but to be 98% sure it works lets call after refreshing JFrame
//refresh JFrame
frame.pack();
frame.revalidate();
frame.repaint();
gp.requestFocusInWindow();
}
}
class GamePanel extends JPanel {
public GamePanel() {
//initiate Jpanel and Keylistener/adapter
}
}
但是你应该使用 Swing KeyBindings(+1 到 @Reimeus 评论)。
阅读此处以熟悉它们:
现在您已经阅读了,让我们展示另一个示例来帮助澄清(尽管 Oracle 做得很好)
如果我们想将KeyBinding 添加到某个JComponent 即JButton for Esc 你可以这样做:
void addKeyBinding(JComponent jc) {
jc.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false), "esc pressed");
jc.getActionMap().put("esc pressed", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent ae) {
System.out.println("Esc pressed");
}
});
jc.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, true), "esc released");
jc.getActionMap().put("esc released", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent ae) {
System.out.println("Esc released");
}
});
}
上面的方法会这样调用:
JButton b=..;//create an instance of component which is swing
addKeyBinding(b);//add keybinding to the component
请注意:
1) 你不需要两个KeyBindings,我只是展示了如何使用Keybindings 获得不同的关键状态并采取适当的行动。
2) 此方法将添加一个Keybinding,只要按下 Esc 并且组件位于具有焦点的窗口中,就会激活该 Keybinding,您可以通过指定另一个 @987654339 来更改它@即:
jc.getInputMap(JComponent.WHEN_FOCUSED).put(..);//will only activated when component has focus