Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p><strong>Disclaimer</strong>: I am not feeling well so this code is horrific, as though.. it too is sick.</p> <p><strong>What I want to happen</strong>: To access DirectInput to obtain a keyboard state, instead of events. That is far beyond the scope of this question though. So we will maintain our own action state.</p> <p>The problem you are having is that you are executing your action within the UI thread. You need to spawn a worker thread and ignore subsequent events until your action is completed.</p> <p>In the example I've given I start a new action when the letter 'a' is pressed or held down. It will not spawn another action until the first action has completed. The action updates a label on the form, displaying how many 'cycles' are left before it has completed. </p> <p>There is also another label that displays how many actions have occurred thus far.</p> <p><strong>Spawning a new action</strong></p> <p>The important part is to let all the UI key events to occur, not blocking in the UI thread causing them to queue up.</p> <pre><code>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(); } } } </code></pre> <p><strong>Updates to the UI Thread</strong></p> <p>If your action performs any kind of updates to the User Interface, it will need to use the <code>SwingUtilities.invokeLater</code> method. This method will queue your code to run in the UI thread. You cannot modify the user interface in a thread other than the UI thread. Also, only use SwingUtilities to update UI components. Any calculations, processing, etc that does not invoke methods on a Component, can be done outside the scope of SwingUtilities.invokeLater. </p> <p><strong>Full Code Listing</strong></p> <pre><code>/* * 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 &lt; 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); } } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload