Прослушивание ключевых событий для иерархии компонентов

У меня есть приложение Swing, которое должно отображать различные наборы элементов управления в зависимости от того, нажаты ли клавиши Control или Alt. Я добавил KeyListener к основному компоненту, но он уведомляется, только если этот компонент выбран, а не если выбран подкомпонент. Есть ли способ прослушать события для компонента и всех потомков?

Редактировать:

Я попытался использовать InputMap основного компонента, но при нажатии клавиши-модификатора событие не вызывалось. В частности, у меня есть следующий код:

InputMap inputMap = panel.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
inputMap.put(KeyStroke.getKeyStroke("pressed CONTROL"), "test1");
inputMap.put(KeyStroke.getKeyStroke("released CONTROL"), "test2");
ActionMap actionMap = panel.getActionMap();
actionMap.put("test1", new AbstractAction() {
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("pressed");
    }
});
actionMap.put("test2", new AbstractAction() {
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("released");
    }
});

При нажатии и отпускании клавиши управления будет напечатано "отпущено", но не "нажато". Ничто больше не регистрирует что-либо в любой InputMap, так что это не так, как будто что-то еще зарегистрировано для того же нажатия клавиши.

4 ответа

Просто поменяй getKeyStroke(...) вызов вроде так:

InputMap inputMap = panel.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_CONTROL, KeyEvent.CTRL_DOWN_MASK, false), "test1");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_CONTROL, 0, true), "test2");
ActionMap actionMap = panel.getActionMap();
actionMap.put("test1", new AbstractAction() {
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("pressed");
    }
});
actionMap.put("test2", new AbstractAction() {
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("released");
    }
});

Я взял много проб и ошибок, чтобы придумать правильное заклинание.

Важно использовать getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT), чтобы иметь возможность прослушивать дочерние и более глубокие виджеты.

Особенно важно уточнить KeyEvent.CTRL_DOWN_MASK, в дополнение к KeyEvent.VK_CONTROL при поиске кнопки управления ПРЕСС событиями. Эта конкретная деталь отсутствовала в вашем примере измененного кода.

Вы можете попытаться использовать связывание ключей, а не KeyListeners. Привязка ключей является конструкцией более высокого уровня и может прослушивать нажатия клавиш, даже если компонент, который "слушает", не имеет фокуса - в отличие от KeyListeners. Вы можете найти больше на них в учебниках Swing: Как использовать привязки клавиш

Вы можете рассмотреть возможность использования InputMap и ActionMap некоторых компонентов Swing. Вы можете указать с JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT чтобы указать, что вы хотите ответить на данное нажатие клавиши, когда компонент или его подкомпоненты находятся в фокусе.

Если вы не хотите использовать InputMap или ActionMap, вы можете просто добавить KeyListener для всех дочерних компонентов:

for (Component child : parent.getComponents())
{
 child.addKeyListener(keyListener);
}

Возможно, вы сможете использовать Global Event Listener.

Другие вопросы по тегам