- How to listen to and take action on keyboard strokes in Java
- Introduction
- The KeyAdapter and KeyEvent classes
- Methods of KeyAdapter class
- The KeyEvent argument
- A keystroke detection application
- Swing, слушаем нажатия клавиш
- Короткие нажатия
- Длинные одновременные нажатия
- Подключаем слушатель
- Живой пример
- KeyListener – обработка событий клавиатуры
- Interface KeyListener
- Method Summary
- Method Details
- keyTyped
- keyPressed
- keyReleased
How to listen to and take action on keyboard strokes in Java
Many candidates are rejected or down-leveled due to poor performance in their System Design Interview. Stand out in System Design Interviews and get hired in 2023 with this popular free course.
Introduction
To detect keystrokes and perform actions in a Java application, we need two classes, KeyAdapter and KeyEvent .
The KeyAdapter and KeyEvent classes
The KeyAdapter class is an abstract class that implements the KeyListener interface; it belongs to the package java.awt.event .
The KeyAdapter class has 3 overridable methods: keyPressed , keyReleased , and keyTyped .
Methods of KeyAdapter class
1. keyPressed method
void keyPressed(KeyEvent e)
Description: The keyPressed function is invoked when a key has been pressed held down on the keyboard. The argument e contains the information of the pressed key.
2. keyReleased method
void keyReleased(KeyEvent e)
Description: The keyReleased function is invoked when a key has been released on the keyboard. The argument e contains the information of the released key.
3. keyTyped method
Description: The keyTyped function is invoked when a key has been pressed and then released on the keyboard. The argument e contains the information of this key.
The KeyEvent argument
All three of the above methods have only one parameter, e of type KeyEvent .
The KeyEvent argument contains the details of which key is pressed. These details can be fetched by invoking the built-in methods defined in the KeyEvent class. The method relevant for our use case is the getKeyCode method, which returns the integer key code value through which the key can be identified.
A keystroke detection application
Let’s say that we want to build an application that detects and prints the pressed arrow key on the standard output. We will start with a boilerplate code for a JFrame application, as follows:
import javax.swing.JFrame; public class Main < public static void main(String[] argv) throws Exception < JFrame myJFrame = new JFrame(); myJFrame.setVisible(true); >>
First, we’ll add the following two import statements at the top:
import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent;
Next, we’ll use the addKeyListener method that is implemented by the JFrame class inside the main function. The addKeyListener function takes an instance of a class that implements KeyListener interface; in our case, this is the KeyAdapter class:
myJFrame.addKeyListener(new KeyAdapter() < >);
Now, inside this new KeyAdapter instance, we’ll override the keyPressed method. This method will check whether the pressed key is one of the arrow keys; if so, an appropriate message will be displayed on the standard output. The code is as follows:
myJFrame.addKeyListener(new KeyAdapter() < public void keyPressed(KeyEvent e) < int keyCode = e.getKeyCode(); if (keyCode == KeyEvent.VK_UP) < System.out.println("Up Arrrow-Key is pressed!"); >else if (keyCode == KeyEvent.VK_DOWN) < System.out.println("Down Arrrow-Key is pressed!"); >else if (keyCode == KeyEvent.VK_LEFT) < System.out.println("Left Arrrow-Key is pressed!"); >else if (keyCode == KeyEvent.VK_RIGHT) < System.out.println("Right Arrrow-Key is pressed!"); >> >);
In the above code, the variable keyCode stores the integer value for the pressed key by invoking the getKeyCode method on e . The following if statements check whether the key is one of the arrow keys; if so, a message is printed onto the standard output specifying which arrow key is pressed.
Note: The KeyEvent.VK_ text represents a static int part of the KeyEvent class. The variables VK_UP , VK_DOWN , VK_LEFT , and VK_RIGHT represent the up, down, left, and right arrow key values respectively.
The following code snippet contains the complete code. You can copy and run it in your preferred IDE:
Swing, слушаем нажатия клавиш
Для прослушивания нажатий клавиш, существует специальный интерфейс KeyListener:
Каждый метод, реализованный интерфейсом KeyListener, вызывается определенным событием, вместе с которым передается экземпляр KeyEvent. KeyEvent содержит в себе всю информацию о нажатой клавише и о модификаторах, таких как Alt, Ctrl, Shift:
int keyCode = event.getKeyCode(); //цифровой код нажатой клавиши boolean isAltDown = event.isAltDown(); boolean isControlDown = event.isControlDown(); boolean isShiftDown = event.isShiftDown();
Дополнительно про KeyEvent можно почитать тут.
У каждой клавиши есть свой цифровой код, например, код пробела 32, клавиша вправо имеет код 39. Всегда можно посмотреть эти коды, выполнив команду:
System.out.println(event.getKeyCode());
Кроме того, класс KeyEvent содержит коды всех клавиш в статических переменных, все они начинаются на VK_
KeyEvent.VK_SPACE; //32 KeyEvent.VK_RIGHT; //39
Можно и нужно использовать эти переменные для сравнения:
If (event.getKeyCode()==KeyEvent.VK_SPACE)
Короткие нажатия
Когда дело касается только обработки нажатой клавиши, достаточно поместить необходимый код в метод keyTyped() интерфейса KeyListener.
@Override public void keyTyped(KeyEvent event) < //клавиша нажата и отпущена >
Длинные одновременные нажатия
Другое дело, когда нам необходимо обрабатывать не только нажатие, но еще и его длительность и скорее всего сразу у нескольких клавиш одновременно. В этом случае приходится вводить дополнительные переменные, на каждую отслеживаемую клавишу:
private boolean isLeft = false; private boolean isRight = false; private boolean isUp = false; private boolean isDown = false;
Такой подход позволяет реализовывать составные действия, например, длительное движение вправо-вверх одновременно. Необходимо правильно отлавливать события с клавиатуры. Когда зажата клавиша, мы получаем событие в метод keyPressed и записываем эту информацию в переменную. С этого момента мы считаем, что клавиша непрерывно нажата. Если клавиша будет отпущена, мы получим событие в метод keyReleased и обновим об этом информацию в переменной.
@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)
Некий движок, управляющий нашей программой и живущий в отдельном потоке не слушает нажатия клавиш напрямую. Вместо этого, он работает с переменными, которые мы любезно для него подготовили.
Подключаем слушатель
Остается только повесить наш класс слушателя нажатий на какой-нибудь компонент Swing, например на JFrame:
frame.addKeyListener(keyListener);
Живой пример
Перед вами код, реализующий отрисовку змейки. Голова управляется «стрелками».
Змейка на Java Swing в 100 строк кода
Листинг RunKeybord.java:
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(); >> > > >
Тут могли располагаться шибко умные слова, великие мысли учёных или изречения скромных блоггеров «jcup.ru». Душераздирающий текст, что заставит прослезиться палача с каменным сердцем. Текст, прочтённый всего лишь раз, способный изменить читателя навсегда. Но, на самом деле, нам нужно было чем-то занять блок внизу.
KeyListener – обработка событий клавиатуры
Работая с приложением, которое имеет графический интерфейс, пользователь прибегает к помощи не только мыши, но и клавиатуры. Java Swing даёт возможность разработчику приложения обработать различные события, которые поступают от клавиатуры в то время, когда пользователь нажимает клавиши. Давайте посмотрим, что необходимо сделать, чтобы иметь возможность слушать события клавиатуры. Для этого рассмотрим интерфейс KeyListener из пакета java.awt.event.
Как в случае и с обработкой других событий, для обработки событий клавиатуры необходимо реализовать специальный интерфейс, а затем добавить получившегося слушателя к интересуемому компоненту. Интерфейс, который нужно реализовать для обработки клавиш был упомянут выше – это КeyListener из пакета java.awt.event. KeyListener имеет три метода: keyTyped, keyPressed и keyReleased.
Когда вызывается каждый из методов системой? Метод keyTyped вызывается системой каждый раз, когда пользователь нажимает на клавиатуре клавиши символы Unicode. Метод keyPressed вызывается системой в случае нажатия любой клавиши на клавиатуре. Метод keyReleased вызывается при отпускании любой клавиши на клавиатуре. Чтобы добавить слушателя KeyListener к интересуемому компоненту для прослушивания событий клавиатуры, используется метод addKeyListener. В качестве параметра методу передается ссылка на слушателя. Для удаления слушателя используется метод removeKeyListener.
Давайте посмотрим, как можно добавить слушателя KeyListener к компоненту в самом простейшем случае.
JTextField textField = new JTextField(20); textField.addKeyListener(new KeyListener() < public void keyPressed(KeyEvent e) < >public void keyReleased(KeyEvent e) < >public void keyTyped(KeyEvent e) < >>);
Здесь создается текстовое поле JTextField. Затем при помощи метода addKeyListener добавляется анонимный слушатель, который реализует все методы интерфейса KeyListener.
Как правило не всегда нужно реализовывать все три метода интерфейса KeyListener. Однако если мы делаем implements KeyListener, то обязаны сделать реализацию каждого метода интерфейса, даже если они будут пустыми. На такой случай есть специальный абстрактный класс KeyAdapter, который содержит все три метода но с пустыми методами keyTyped, keyPressed и keyReleased. Тогда достаточно будет пронаследоваться от KeyAdapter и переопределить в нем только требуемый метод.
Если нет необходимости реализовывать все методы KeyListener, то можно сделать вот так:
textField.addKeyListener(new KeyAdapter() < public void keyPressed(KeyEvent e) < >>);
Каждый раз, когда пользователь нажимает клавиши на клавиатуре и система вызывает методы keyTyped, keyPressed и keyReleased, в качестве параметра им передается объект KeyEvent, который содержит всю необходимую информацию о произошедшем событии. Отсюда можно узнать код клавиши, которая была нажата – метод getKeyCode. Были ли зажаты при этом такие клавиши, как Alt, Shift или Ctrl. Проверить это можно вызвав соответственно методы isAltDown, isShiftDown и isControlDown. Класс KeyEvent содержит большой набор констант. Каждая константа содержит код соответствующей клавиши. Поэтому нет необходимости коды всех клавиш. Достаточно использовать какую-то из констант. По названиям констант можно легко определить, какой клавише она соответствует. Например KeyEvent. VK_ENTER или KeyEvent.VK_F.
Стоит сказать, что события от клавиатуры будут генерироваться системой только тогда, когда компонент, который мы слушаем, находится в фокусе.
Посмотрим теперь на тестовый пример.
Здесь происходит обработки нажатия клавиш компонентом JPanel. Вообще по умолчанию JPanel не должен получать фокуса, однако это можно зделать, если очень захотеть при помощи метода setFocusable и передать этому методу true в качестве параметра.
import java.awt.Dimension; import java.awt.Font; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; public class TestFrame extends JFrame < private JLabel label; public TestFrame() < super("Test frame"); createGUI(); >public void createGUI() < setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JPanel panel = new JPanel(); panel.setLayout(new BorderLayout()); panel.setFocusable(true); label = new JLabel(); label.setFont(new Font("Calibri", Font.PLAIN, 20)); label.setHorizontalAlignment(JLabel.CENTER); panel.addKeyListener(new KeyAdapter() < public void keyReleased(KeyEvent e) < label.setText(e.getKeyText(e.getKeyCode())); >>); panel.add(label, BorderLayout.CENTER); setPreferredSize(new Dimension(200, 200)); getContentPane().add(panel); > public static void main(String[] args) < javax.swing.SwingUtilities.invokeLater(new Runnable() < public void run() < JFrame.setDefaultLookAndFeelDecorated(true); TestFrame frame = new TestFrame(); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); >>); > >
Interface KeyListener
The listener interface for receiving keyboard events (keystrokes). The class that is interested in processing a keyboard event either implements this interface (and all the methods it contains) or extends the abstract KeyAdapter class (overriding only the methods of interest).
The listener object created from that class is then registered with a component using the component’s addKeyListener method. A keyboard event is generated when a key is pressed, released, or typed. The relevant method in the listener object is then invoked, and the KeyEvent is passed to it.
Method Summary
Method Details
keyTyped
Invoked when a key has been typed. See the class description for KeyEvent for a definition of a key typed event.
keyPressed
Invoked when a key has been pressed. See the class description for KeyEvent for a definition of a key pressed event.
keyReleased
Invoked when a key has been released. See the class description for KeyEvent for a definition of a key released event.
Report a bug or suggest an enhancement
For further API reference and developer documentation see the Java SE Documentation, which contains more detailed, developer-targeted descriptions with conceptual overviews, definitions of terms, workarounds, and working code examples. Other versions.
Java is a trademark or registered trademark of Oracle and/or its affiliates in the US and other countries.
Copyright © 1993, 2023, Oracle and/or its affiliates, 500 Oracle Parkway, Redwood Shores, CA 94065 USA.
All rights reserved. Use is subject to license terms and the documentation redistribution policy.