2008-11-13 11 views
75

Я пытаюсь реализовать 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 не получает каких-либо событий. Но, я уверен, что так оно и есть.

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

ответ

45

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

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

myComponent.addKeyListener(new KeyListener ...); 

Примечание: Некоторые компоненты не Focusable как JLabel.

Для установки их Focusable вам нужно:

myComponent.setFocusable(true); 
+1

Да, вы были правы, когда вы запускаете программу, вы можете немного увидеть, что фокус находится на кнопке A. добавление ключа для каждой кнопки фиксировало это. это немного странно, я думаю, что добавление keylistener в JFrame будет работать, но я думаю, нет. Благодаря! – Tomek

+0

Я сделал прослушиватель на JFrame, который прослушивается с клавиатуры. Я хочу, чтобы он работал в пассивном режиме, даже если окно не спереди (сфокусировано). JFrame не прослушивается в пассивном режиме. – Usman

3

Хм .. для какого класса ваш конструктор? Возможно, какой-то класс расширяет 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); 
    } 
} 
+0

Я получаю все выходные данные сообщений также. Запустите в командной строке Windows. – Darrel

+1

Вы получаете все сообщения, потому что в этом примере JFrame имеет фокус. попробуйте добавить компонент TextBox в JFrame и посмотреть, что произойдет. –

10

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

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

Подробнее о том, что вы должны сделать, см. Мой ответ на странице Application wide keyboard shortcut - Java Swing.

10

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

JFrame.setFocusable(true); 

Good Luck

+1

Я обнаружил, что это работает только до тех пор, пока я не использую что-то, что есть на моем JFrame, тогда KeyListener больше не отвечает – user3328784

124

Если вы не хотите, чтобы зарегистрировать слушателя на каждом компоненте,
вы можете добавить свой собственный 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); 
    } 
} 
+4

KeyboardFocusManager - это приложение, если у вас много кадров, у вас появятся проблемы? – neoedmund

+1

Так что это должно сработать, например: foreach («фокусируемые компоненты в кадре» как _) {_.addkeylistener (frameKeylistener);} – neoedmund

2

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

myChildOfJFrame.requestFocusInWindow(); 

на ваш основной метод, после того, как вы создали свой экземпляр вашего подкласса JFrame и его видимым.

+0

спасибо, имел ту же проблему. странно компонент теряет фокус, даже если это область содержимого ... – Androbin

8

Deion (и кто-либо другой задает аналогичный вопрос), вы можете использовать код Питера выше, но вместо того, чтобы печатать на стандартный вывод, вы проверяете код клавиши 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; 
} 
4

для захвата ключевых событий всех текстовых полей в 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; 
    } 
} 
+0

Для рабочего примера вы можете подумать о добавлении импорта. Обычно я добавляю «импорт пакетов», чтобы держать их короткими. В противном случае +1. Интересная техника. –

-1

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

addKeyListener (это);

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

+7

Вы должны действительно объяснить «правильное место», чтобы сделать этот ответ полезным. – Till

-1

Возможно, пользовательские JComponents установили родительский JFrame для фокусировки.

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

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

+2

-1 определенно нет - это полное <строгое цензурное слово> в более чем одном отношении: а) непристойное подклассов; б) неприличное обращение ссылки; в) неуместное изменение состояния при покраске. Г) .. – kleopatra

15

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

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

Этот код вызовет dispose() на JFrame, когда клавиша escape будет нажата в любом месте окна. 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); 
3

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

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"); 
     } 
    }); 
+0

Лучшее Slution Ever. Спасибо. – biv