这个键绑定我做错了什么?

What am I doing wrong with this key binding?

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

class Menu{

  JFrame frame = new JFrame();
  Image icon = Toolkit.getDefaultToolkit().getImage("image1.png");
  Action escapePressed;
  
  public Menu() {
    frame.setVisible(true);
    frame.setIconImage(icon);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setMinimumSize(new Dimension(500, 500));
    frame.setTitle("Nine Games");
    frame.setFocusable(true);
    frame.setResizable(true);
    frame.add(new StartScreen());

    escapePressed = new EscapePressed();

    frame.getInputMap().put(KeyStroke.getKeyStroke('w'), "escapePressed");
    frame.getActionMap().put("escapePressed", escapePressed);
  }

  public class EscapePressed extends AbstractAction {
    @Override
    public void actionPerformed(ActionEvent e) {
      System.out.println("Escape Pressed");
      System.exit(0);
    }
  }
}

我不知道为什么,但是这个程序说 getInputMapgetActionMap 不存在。这很奇怪。我可以发誓我把它全部正确地输入了。我什至遵循了教程,但似乎没有任何效果。

我不想使用 KeyStroke.getKeyStroke,因为在如何触发击键方面存在一定程度的歧义,这是个人问题,但我浪费了太多时间尝试调试相关问题

相反,我更喜欢使用 KeyStroke.getKeyStroke(KeyEvent.VK_W, 0)。这(对我而言)更容易理解,我也可以通过它配置“按下”或“释放”功能。

getInputMap() 的默认行为是生成事件 WHEN_FOCUSED,这与您对 KeyListener 的期望相同,但您要将键绑定添加到 JFrame,它不太可能获得焦点(它是一个复合组件,因此这样做没有意义)。

相反,您应该尝试类似...

frame.getInputMap(WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0), "escapePressed");
frame.getActionMap().put("escapePressed", escapePressed);

现在,就我个人而言,我认为通过将组件添加到框架中来维护这种东西可能会更好,但这就是我。

几个问题:

  1. a JFrame 没有 InputMap 和 ActionMap。只有从 JComponent 扩展的组件才能使用键绑定。因此,要处理退出 KeyStroke,您可能想使用 JRootPane 添加绑定
  2. 您不想使用默认的 WHEN_FOCUSED InputMap,因为根窗格不会获得焦点,因为您添加到框架的其他一些组件将获得焦点。相反,您想使用 WHEN_IN_FOCUSED_WINDOW InputMap.

所以你的代码可能是这样的:

//frame.getInputMap().put(KeyStroke.getKeyStroke('w'), "escapePressed");
//frame.getActionMap().put("escapePressed", escapePressed);    
frame.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke('w'), "escapePressed");
frame.getRootPane().getActionMap().put("escapePressed", escapePressed);

阅读 How to Use Key Bindings 上的 Swing 教程部分了解更多信息。

另请查看 Using Top Level Containers 了解有关根窗格的更多信息。