为什么键绑定不适用于 CardLayout?

Why are the keybindings not working with CardLayout?

在我的问题中 Frakcool 给了我使用键绑定的建议,但有一件事没有奏效:当 JButton 将另一个 JPanel 放在框架的前面时,键绑定没有响应。这是代码:

private JFrame frame;
private JPanel[] statePanels;
private CardLayout layout;
private JPanel mainPanel;
private JButton button;
private String status;

void initAndShow()
{
    //Init stuff
    mainPanel = new JPanel(layout);
    statePanels = new JPanel[2];
    button = new JButton("Exit");
    status = "Menu";

    button.addActionListener(e -> {
        status = status.equals("Menu") ? "World" : "Menu";
        layout.show(mainPanel, status);
    });

    statePanels[0] = new OutWorldHandler();
    statePanels[1] = new InWorldHandler();

    mainPanel.add(statePanels[0], "Menu");
    mainPanel.add(statePanels[1], "World");

    mainPanel.getInputMap().put(KeyStroke.getKeyStroke('f'), "close");
    mainPanel.getActionMap().put("close", this);

    frame.add(mainPanel);
    frame.add(button, BorderLayout.SOUTH);
}

@Override
public void actionPerformed(ActionEvent e)
{
    System.out.println("hi");
}

预期的输出是,当我一直按下 f 时,控制台会打印出 "hi",但只有当我没有按下按钮时才会打印

对我有用的解决方案:我只是在 button.addActionListener lambda 中添加了一条语句,将焦点放在 mainPanel 上:mainPanel.grabFocus();.

完整的代码看起来像这样:

button.addActionListener(e -> {
    status = status.equals("Menu") ? "World" : "Menu";

    layout.show(mainPanel, status);
    button.setText("Exit " + status);
    mainPanel.grabFocus();
});

键绑定不是特别复杂,但可能需要一点时间才能习惯。为此,手头有How to Use Key Bindings and the JavaDocs for JComponent,以供参考。

键绑定的目标之一 API 是可配置性,使我们能够更好地控制确定击键何时应触发事件。

JComponent#getInputMap 方法 returns 绑定到 "when has focused" 上下文的映射。这意味着在触发绑定之前组件需要有焦点(并且显然是可聚焦的)。

如果您希望在不同级别触发绑定,则需要使用 JComponent#getInputMap(int) 并将其传递给三个可用上下文之一:

你使用哪个取决于你的需要,但我通常很懒,当我想要 "global" 状态时就选择 JComponent.WHEN_IN_FOCUSED_WINDOW