면책 사항 : 나는이 느낌이 좋지 않아서이 코드가 끔찍한 것처럼 보입니다.
내가 원하는 것 : DirectInput에 액세스하여 이벤트 대신 키보드 상태를 얻습니다. 그것은이 질문의 범위를 훨씬 벗어납니다. 그래서 우리는 우리 자신의 행동 상태를 유지할 것입니다.
발생하는 문제는 UI 스레드 내에서 작업을 실행하고 있다는 것입니다. 작업자 스레드를 생성하고 작업이 완료 될 때까지 후속 이벤트를 무시해야합니다.
예를 들어, 문자 'a'를 누르거나 누르고있을 때 새로운 작업을 시작합니다. 첫 번째 작업이 완료 될 때까지 다른 작업을 생성하지 않습니다. 작업은 양식의 레이블을 업데이트하여 완료되기 전에 남아있는 '주기'수를 표시합니다.
지금까지 얼마나 많은 작업이 발생했는지 표시하는 또 다른 레이블이 있습니다. 중요한 부분은 모든 UI 키 이벤트가 그들을 대기열 원인이 UI 스레드에서 차단하지, 발생하도록하는 것입니다 새로운 액션
을 산란
.
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();
}
}
}
업데이트 UI 스레드 액션은 사용자 인터페이스 업데이트의 모든 종류를 수행하는 경우
에, 그것은 SwingUtilities.invokeLater
방법을 사용해야합니다. 이 메서드는 UI 스레드에서 실행되도록 코드를 대기열에 추가합니다. UI 스레드가 아닌 스레드에서 사용자 인터페이스를 수정할 수 없습니다. 또한 SwingUtilities를 사용하여 UI 구성 요소를 업데이트하십시오. Component에서 메소드를 호출하지 않는 계산, 처리 등은 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);
}
}
감사합니다. 이것은 완벽하게 작동했습니다. – Jon