Swing, слушаем нажатия клавиш

Для прослушивания нажатий клавиш, существует специальный интерфейс KeyListener:
1 2 3 4 5 6 7 8 9 10 | interface KeyListener { //клавиша нажата, но не отпущена public void keyPressed(KeyEvent event); //клавиша отпущена public void keyReleased(KeyEvent event); //клавиша нажата и отпущена public void keyTyped(KeyEvent event); } |
Каждый метод, реализованный интерфейсом KeyListener, вызывается определенным событием, вместе с которым передается экземпляр KeyEvent. KeyEvent содержит в себе всю информацию о нажатой клавише и о модификаторах, таких как Alt, Ctrl, Shift:
1 2 3 4 | int keyCode = event.getKeyCode(); //цифровой код нажатой клавиши boolean isAltDown = event.isAltDown(); boolean isControlDown = event.isControlDown(); boolean isShiftDown = event.isShiftDown(); |
Дополнительно про KeyEvent можно почитать тут.
У каждой клавиши есть свой цифровой код, например, код пробела 32, клавиша вправо имеет код 39. Всегда можно посмотреть эти коды, выполнив команду:
1 | System.out.println(event.getKeyCode()); |
Кроме того, класс KeyEvent содержит коды всех клавиш в статических переменных, все они начинаются на VK_
1 2 | KeyEvent.VK_SPACE; //32 KeyEvent.VK_RIGHT; //39 |
Можно и нужно использовать эти переменные для сравнения:
1 2 3 | If (event.getKeyCode()==KeyEvent.VK_SPACE) { System.out.println(Нажат пробел); } |
Короткие нажатия
Когда дело касается только обработки нажатой клавиши, достаточно поместить необходимый код в метод keyTyped() интерфейса KeyListener.
1 2 3 4 | @Override public void keyTyped(KeyEvent event) { //клавиша нажата и отпущена } |
Длинные одновременные нажатия
Другое дело, когда нам необходимо обрабатывать не только нажатие, но еще и его длительность и скорее всего сразу у нескольких клавиш одновременно. В этом случае приходится вводить дополнительные переменные, на каждую отслеживаемую клавишу:
1 2 3 4 | private boolean isLeft = false ; private boolean isRight = false ; private boolean isUp = false ; private boolean isDown = false ; |
Такой подход позволяет реализовывать составные действия, например, длительное движение вправо-вверх одновременно. Необходимо правильно отлавливать события с клавиатуры. Когда зажата клавиша, мы получаем событие в метод keyPressed и записываем эту информацию в переменную. С этого момента мы считаем, что клавиша непрерывно нажата. Если клавиша будет отпущена, мы получим событие в метод keyReleased и обновим об этом информацию в переменной.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | @Override public void keyPressed(KeyEvent event) { if (e.getKeyCode()==KeyEvent.VK_LEFT) isLeft = true ; if (e.getKeyCode()==KeyEvent.VK_RIGHT) isRight = true ; if (e.getKeyCode()==KeyEvent.VK_UP) isUp = true ; if (e.getKeyCode()==KeyEvent.VK_DOWN) isDown = true ; } @Override public void keyReleased(KeyEvent event) { if (e.getKeyCode()==KeyEvent.VK_LEFT) isLeft = false ; if (e.getKeyCode()==KeyEvent.VK_RIGHT) isRight = false ; if (e.getKeyCode()==KeyEvent.VK_UP) isUp = false ; if (e.getKeyCode()==KeyEvent.VK_DOWN) isDown = false ; } |
Некий движок, управляющий нашей программой и живущий в отдельном потоке не слушает нажатия клавиш напрямую. Вместо этого, он работает с переменными, которые мы любезно для него подготовили.
Подключаем слушатель
Остается только повесить наш класс слушателя нажатий на какой-нибудь компонент Swing, например на JFrame:
1 | frame.addKeyListener(keyListener); |
Живой пример
Перед вами код, реализующий отрисовку змейки. Голова управляется "стрелками".

Листинг RunKeybord.java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | package ru.jcup.education.graphics.swing; import java.awt.*; import java.awt.event.*; import java.util.Random; import javax.swing.JFrame; public class RunKeyboard extends JFrame implements KeyListener{ private Thread thread; private static Random random = new Random(); private static final int DIR_STEP = 2 ; private boolean isLeft = false ; private boolean isRight = false ; private boolean isUp = false ; private boolean isDown = false ; private int x, y; public RunKeyboard( int width, int height) { this .setSize(width, height); x = width/ 2 ; y = height/ 2 ; this .addKeyListener( this ); thread = new MoveThread( this ); thread.start(); } //Start point public static void main(String... string) { JFrame frame = new RunKeyboard( 500 , 500 ); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible( true ); } //Listener @Override public void keyPressed(KeyEvent e) { if (e.getKeyCode()==KeyEvent.VK_LEFT) isLeft = true ; if (e.getKeyCode()==KeyEvent.VK_RIGHT) isRight = true ; if (e.getKeyCode()==KeyEvent.VK_UP) isUp = true ; if (e.getKeyCode()==KeyEvent.VK_DOWN) isDown = true ; } @Override public void keyReleased(KeyEvent e) { if (e.getKeyCode()==KeyEvent.VK_LEFT) isLeft = false ; if (e.getKeyCode()==KeyEvent.VK_RIGHT) isRight = false ; if (e.getKeyCode()==KeyEvent.VK_UP) isUp = false ; if (e.getKeyCode()==KeyEvent.VK_DOWN) isDown = false ; } @Override public void keyTyped(KeyEvent arg0) {} //Graphics @Override public void paint(Graphics gr) { Graphics2D g2d = (Graphics2D)gr; int r = random.nextInt( 256 ); int g = random.nextInt( 256 ); int b = random.nextInt( 256 ); g2d.setColor( new Color(r,g,b)); g2d.setStroke( new BasicStroke(4f)); g2d.drawOval(x- 25 , y- 25 , 50 , 50 ); } public void animate() { if (isLeft) x-=DIR_STEP; if (isRight) x+=DIR_STEP; if (isUp) y-=DIR_STEP; if (isDown) y+=DIR_STEP; this .repaint(); } //Engine thread private class MoveThread extends Thread{ RunKeyboard runKeyboard; public MoveThread(RunKeyboard runKeyboard) { super ( "MoveThread" ); this .runKeyboard = runKeyboard; } public void run(){ while ( true ) { runKeyboard.animate(); try { Thread.sleep( 10 ); } catch (InterruptedException e) { e.printStackTrace(); } } } } } |