Невосприимчивый KeyListener для JFrame

Я пытаюсь реализовать KeyListener для моего JFrame. В конструкторе я использую этот код:

System.out.println("test");
addKeyListener(new KeyListener() {
    public void keyPressed(KeyEvent e) { System.out.println( "tester"); }

    public void keyReleased(KeyEvent e) { System.out.println("2test2"); }

    public void keyTyped(KeyEvent e) { System.out.println("3test3"); }
});

Когда я запустил его, сообщение test появляется в моей консоли. Однако, когда я нажимаю клавишу, я не получаю никаких других сообщений, как будто KeyListener там даже не было.

Я думал, что это может быть потому, что фокус не на JFrame
и поэтому они KeyListener не получают никаких событий. Но, я уверен, что это так.

Есть ли что-то, что мне не хватает?

Ответ 1

Вы должны добавить свой keyListener для каждого компонента, который вам нужен. Эти компоненты будут отправлять только компонент с фокусом. Например, если в вашем JFrame есть только один TextBox, то TextBox имеет фокус. Поэтому вы также должны добавить KeyListener к этому компоненту.

Процесс тот же:

myComponent.addKeyListener(new KeyListener ...);

Примечание. Некоторые компоненты не настраиваются, как JLabel.

Для настройки фокусировки вам необходимо:

myComponent.setFocusable(true);

Ответ 2

Если вы не хотите регистрировать слушателя на каждом компоненте,
вы можете добавить свой KeyEventDispatcher в KeyboardFocusManager:

public class MyFrame extends JFrame {    
    private class MyDispatcher implements KeyEventDispatcher {
        @Override
        public boolean dispatchKeyEvent(KeyEvent e) {
            if (e.getID() == KeyEvent.KEY_PRESSED) {
                System.out.println("tester");
            } else if (e.getID() == KeyEvent.KEY_RELEASED) {
                System.out.println("2test2");
            } else if (e.getID() == KeyEvent.KEY_TYPED) {
                System.out.println("3test3");
            }
            return false;
        }
    }
    public MyFrame() {
        add(new JTextField());
        System.out.println("test");
        KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
        manager.addKeyEventDispatcher(new MyDispatcher());
    }

    public static void main(String[] args) {
        MyFrame f = new MyFrame();
        f.pack();
        f.setVisible(true);
    }
}

Ответ 3

InputMaps и ActionMaps были предназначены для захвата ключевых событий для компонента, его и всех его подкомпонентов или всего окна. Это контролируется с помощью параметра в JComponent.getInputMap(). См. Как использовать привязки клавиш для документации.

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

Этот код будет вызывать dispose() в JFrame, когда ключ побега попадает в любом месте окна. JFrame не является результатом JComponent, поэтому вам нужно использовать другой компонент в JFrame для создания привязки ключа. Область содержимого может быть таким компонентом.

InputMap inputMap; 
ActionMap actionMap;
AbstractAction action;
JComponent component;

inputMap  = component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
actionMap = component.getActionMap();

action    = new AbstractAction()
{
   @Override
   public void actionPerformed(ActionEvent e)
   {
      dispose();
   }
};

inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "dispose");
actionMap.put("dispose", action);

Ответ 4

KeyListener является низким уровнем и применяется только к одному компоненту. Несмотря на попытки сделать его более удобным, JFrame создает ряд компонентных компонентов, наиболее очевидным из которых является область содержимого. JComboBox Пользовательский интерфейс также часто реализуется аналогичным образом.

Стоит отметить, что события мыши работают странным образом, немного отличающимся от ключевых событий.

Подробнее о том, что вы должны сделать, см. мой ответ на Широкоэкранный набор приложений - Java Swing.

Ответ 5

У меня такая же проблема, пока я не прочитал, что настоящая проблема связана с FOCUS, что ваш JFrame уже добавил Listeners, но кадр тура никогда не фокусируется на фокусе, потому что у вас есть много компонентов внутри вашего JFrame, которые также можно сфокусировать, поэтому попробуйте:

JFrame.setFocusable(true);

Удача

Ответ 6

Deion (и кто-то еще задает аналогичный вопрос), вы можете использовать вышеприведенный код Peter, но вместо печати на стандартный вывод вы тестируете key code PRESSED, RELEASED или TYPED.

@Override
public boolean dispatchKeyEvent(KeyEvent e) {
    if (e.getID() == KeyEvent.KEY_PRESSED) {
        if (e.getKeyCode() == KeyEvent.VK_F4) {
            dispose();
        }
    } else if (e.getID() == KeyEvent.KEY_RELEASED) {
        if (e.getKeyCode() == KeyEvent.VK_F4) {
            dispose();
        }
    } else if (e.getID() == KeyEvent.KEY_TYPED) {
        if (e.getKeyCode() == KeyEvent.VK_F4) {
            dispose();
        }
    }
    return false;
}

Ответ 7

чтобы фиксировать ключевые события всех текстовых полей в JFrame, можно использовать обработчик сообщений с ключевым событием. Вот рабочий пример, после добавления очевидного включает.

public class KeyListenerF1Demo extends JFrame implements KeyEventPostProcessor {
    public static final long serialVersionUID = 1L;

    public KeyListenerF1Demo() {
        setTitle(getClass().getName());

        // Define two labels and two text fields all in a row.
        setLayout(new FlowLayout());

        JLabel label1 = new JLabel("Text1");
        label1.setName("Label1");
        add(label1);

        JTextField text1 = new JTextField(10);
        text1.setName("Text1");
        add(text1);

        JLabel label2 = new JLabel("Text2");
        label2.setName("Label2");
        add(label2);

        JTextField text2 = new JTextField(10);
        text2.setName("Text2");
        add(text2);

        // Register a key event post processor.
        KeyboardFocusManager.getCurrentKeyboardFocusManager()
                .addKeyEventPostProcessor(this);
    }

    public static void main(String[] args) {
        JFrame f = new KeyListenerF1Demo();
        f.setName("MyFrame");
        f.pack();
        f.setVisible(true);
    }

    @Override
    public boolean postProcessKeyEvent(KeyEvent ke) {
        // Check for function key F1 pressed.
        if (ke.getID() == KeyEvent.KEY_PRESSED
                && ke.getKeyCode() == KeyEvent.VK_F1) {

            // Get top level ancestor of focused element.
            Component c = ke.getComponent();
            while (null != c.getParent())
                c = c.getParent();

            // Output some help.
            System.out.println("Help for " + c.getName() + "."
                    + ke.getComponent().getName());

            // Tell keyboard focus manager that event has been fully handled.
            return true;
        }

        // Let keyboard focus manager handle the event further.
        return false;
    }
}

Ответ 8

Хм.. для какого класса ваш конструктор? Возможно, какой-то класс расширяет JFrame? Фокус окна должен быть в окне, конечно, но я не думаю, что проблема.

Я расширил ваш код, попытался запустить его, и он сработал - нажатия клавиш были получены в результате вывода на печать. (запустите с помощью Ubuntu через Eclipse):

public class MyFrame extends JFrame {
    public MyFrame() {
        System.out.println("test");
        addKeyListener(new KeyListener() {
            public void keyPressed(KeyEvent e) {
                System.out.println("tester");
            }

            public void keyReleased(KeyEvent e) {
                System.out.println("2test2");
            }

            public void keyTyped(KeyEvent e) {
                System.out.println("3test3");
            }
        });
    }

    public static void main(String[] args) {
        MyFrame f = new MyFrame();
        f.pack();
        f.setVisible(true);
    }
}

Ответ 9

Это должно помочь

    yourJFrame.setFocusable(true);
    yourJFrame.addKeyListener(new java.awt.event.KeyAdapter() {


        @Override
        public void keyTyped(KeyEvent e) {
            System.out.println("you typed a key");
        }

        @Override
        public void keyPressed(KeyEvent e) {
            System.out.println("you pressed a key");
        }

        @Override
        public void keyReleased(KeyEvent e) {
            System.out.println("you released a key");
        }
    });

Ответ 10

У меня была такая же проблема. Я последовал за советом Бруно и обнаружил, что добавление KeyListener только к "первой" кнопке в JFrame (то есть в левом верхнем углу) сделало трюк. Но я согласен с вами, что это своего рода тревожное решение. Поэтому я пошарил и обнаружил более аккуратный способ исправить ситуацию. Просто добавьте строку

myChildOfJFrame.requestFocusInWindow();

к вашему основному методу после создания вашего экземпляра вашего подкласса JFrame и его отображения.

Ответ 11

lol.... все, что вам нужно сделать, это убедиться, что

addKeyListener (это);

правильно помещается в ваш код.

Ответ 12

У вас могут быть настраиваемые JComponents, которые устанавливают родительский JFrame.

Просто добавьте конструктор и перейдите в JFrame. Затем сделайте вызов setFocusable() в paintComponent.

Таким образом, JFrame всегда будет получать KeyEvents, независимо от того, нажаты ли другие компоненты.