Почему сочетания клавиш не работают с CardLayout? - PullRequest
0 голосов
/ 23 января 2019

В моем вопросе Как мне нарисовать JPanel из нескольких внешних классов? 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, консоль будет выводить «привет», но это продолжалось только до тех пор, пока я не нажал кнопку

Ответы [ 2 ]

0 голосов
/ 23 января 2019

Связывание клавиш не очень сложное, но может потребоваться немного привыкнуть. Для этого полезно иметь под рукой Как использовать привязки клавиш и JavaDocs для JComponent для справки.

Одной из целей API привязок клавиш является конфигурируемость, позволяющая нам лучше контролировать, когда нажатие клавиши должно вызывать событие.

Метод JComponent#getInputMap возвращает отображение, которое привязано к контексту «когда был сосредоточен». Это означает, что компонент должен иметь фокус (и, очевидно, должен быть фокусируемым), прежде чем будет активирована привязка.

Если вы хотите, чтобы привязка сработала на другом уровне, вам нужно использовать JComponent#getInputMap(int) и передать ему один из трех доступных контекстов:

То, что вы используете, будет зависеть от ваших потребностей, но я, как правило, ленив и иду на JComponent.WHEN_IN_FOCUSED_WINDOW, когда я хочу "глобальное" состояние

0 голосов
/ 23 января 2019

Решение, которое сработало для меня: я просто добавил в лямбду button.addActionListener утверждение, в котором акцент был сделан на mainPanel: mainPanel.grabFocus();.

Затем полный код выглядел примерно так:

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

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