Отказ от ответственности : Я плохо себя чувствую, поэтому этот код ужасен, как будто ... он тоже болен.
Что я хочу, чтобы произошло : Чтобы получить доступ к DirectInput для получения состояния клавиатуры, а не событий. Это далеко за рамки этого вопроса, хотя. Таким образом, мы будем поддерживать наше собственное состояние действия.
Проблема в том, что вы выполняете свое действие в потоке пользовательского интерфейса. Вам нужно порождать рабочий поток и игнорировать последующие события, пока ваше действие не будет завершено.
В приведенном мной примере я начинаю новое действие, когда буква «а» нажата или удерживается нажатой. Это не будет порождать другое действие, пока первое действие не будет завершено. Действие обновляет метку в форме, показывая, сколько «циклов» осталось до ее завершения.
Существует также еще одна метка, которая показывает, сколько действий было выполнено до сих пор.
Создание нового действия
Важная часть заключается в том, чтобы все события ключа пользовательского интерфейса происходили, а не блокировались в потоке пользовательского интерфейса, заставляя их стоять в очереди.
public void keyPressed(KeyEvent e) {
char keyChar = e.getKeyChar();
System.out.println("KeyChar: " + keyChar);
// Press a to start an Action
if (keyChar == 'a') {
if (!mAction.isRunning()) {
mTotalActions.setText("Ran " + (++mTotalActionsRan) + " actions.");
System.out.println("Starting new Action");
Thread thread = new Thread(new Runnable() {
public void run() {
mAction.run();
}
});
thread.start();
}
}
}
Обновления в потоке пользовательского интерфейса
Если ваше действие выполняет какие-либо обновления пользовательского интерфейса, необходимо использовать метод SwingUtilities.invokeLater
. Этот метод поставит ваш код в очередь для запуска в потоке пользовательского интерфейса. Вы не можете изменить пользовательский интерфейс в потоке, отличном от потока пользовательского интерфейса. Кроме того, используйте только SwingUtilities для обновления компонентов пользовательского интерфейса. Любые вычисления, обработка и т. Д., Которые не вызывают методы для Компонента, могут выполняться вне области SwingUtilities.invokeLater.
Полный список кодов
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package stackoverflow_4589538;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
public class Main extends JFrame {
private JLabel mActionLabel;
private JLabel mTotalActions;
private int mTotalActionsRan;
private class MyAction {
private boolean mIsRunning = false;
public void run() {
// Make up a random wait cycle time
final int cycles = new Random().nextInt(100);
for (int i = 0; i < cycles; ++i) {
final int currentCycle = i;
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
mActionLabel.setText("Cycle " + currentCycle + " of " + cycles);
}
});
}
completed();
}
public synchronized void start() {
mIsRunning = true;
}
public synchronized void completed() {
mIsRunning = false;
}
public synchronized boolean isRunning() {
return mIsRunning;
}
}
private MyAction mAction = new MyAction();
public Main() {
setLayout(null);
setBounds(40, 40, 800, 600);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
char keyChar = e.getKeyChar();
System.out.println("KeyChar: " + keyChar);
// Press A to start an Action
if (keyChar == 'a') {
if (!mAction.isRunning()) {
mTotalActions.setText("Ran " + (++mTotalActionsRan) + " actions.");
System.out.println("Starting new Action");
Thread thread = new Thread(new Runnable() {
public void run() {
mAction.run();
}
});
// I had this within the run() method before
// but realized that it is possible for another UI event
// to occur and spawn another Action before, start() had
// occured within the thread
mAction.start();
thread.start();
}
}
}
@Override
public void keyReleased(KeyEvent e) {
}
});
mActionLabel = new JLabel();
mActionLabel.setBounds(10, 10, 150, 40);
mTotalActions = new JLabel();
mTotalActions.setBounds(10, 50, 150, 40);
add(mActionLabel);
add(mTotalActions);
}
public static void main(String[] args) {
new Main().setVisible(true);
}
}