Прослушивание ключевых событий для иерархии компонентов - PullRequest
6 голосов
/ 03 февраля 2011

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

Edit:

Я пытался использовать 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 ]

4 голосов
/ 24 февраля 2013

Просто измените ваш 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 при поиске управляющих событий PRESS.Эта конкретная деталь отсутствовала в вашем примере измененного кода.

2 голосов
/ 03 февраля 2011

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

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

for (Component child : parent.getComponents())
{
 child.addKeyListener(keyListener);
}
2 голосов
/ 03 февраля 2011

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

1 голос
/ 03 февраля 2011

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

...