Прослушивание ключевых событий для иерархии компонентов
У меня есть приложение 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);
}