Disclaimer : I am not feeling well so this code is horrific, as though.. it too is sick What I want to happen : 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 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 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 There is also another label that displays how many actions have occurred thus far Spawning a new action The important part is to let all the UI key events to occur, not blocking in the UI thread causing them to queue up 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(); } } } Updates to the UI Thread If your action performs any kind of updates to the User Interface, it will need to use the SwingUtilities. InvokeLater 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 Full Code Listing 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 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); } }.
Disclaimer: I am not feeling well so this code is horrific, as though.. it too is sick. What I want to happen: 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.
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.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. There is also another label that displays how many actions have occurred thus far. Spawning a new action The important part is to let all the UI key events to occur, not blocking in the UI thread causing them to queue up.
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(); } } } Updates to the UI Thread If your action performs any kind of updates to the User Interface, it will need to use the SwingUtilities. InvokeLater 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. Full Code Listing /* * 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 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); } }.
Thanks, this worked perfectly. – Jon Jan 4 at 16:08.
I also noticed that the keyRelease event doesn't occur until after the final keyPress event is processed regardless of when the key was actually released This depends on the OS you are using. This is the behaviour on Windows (which makes sense to me). On Unix or Mac I believe you get multiple keyPressed, keyReleased events.So you solution should not be based on keyReleased events.
I have a program where the user can press a key to perform an action. Then you should be using Key Binding, not a KeyListener. Read the section from the Swing tutorial on How to Use Key Bindings for more information.
When the Action is invoked you can then disable it. I'm not sure if this will prevent the KeyStroke from working again or whether you will still need to check the enabled state of the Action. Then when the Action code is finished executing you can re-enable the Action.
Also, this long running code should not execute on the EDT. Read the section from the Swing tutorial on Concurrency for more information about this and for solutions.
For all we know he could be developing a simple video game and wants to move a character a certain distance, which is taking some time. From my understanding he wants an action to occur as long as he is holding down a key. Although I could of misread what he said.
– Andrew Finnell Jan 4 at 3:58 You are right, I'm actually doing an imaging app, and I want to be able to hold down a key and change the image plane the user is looking at, and I want to stop moving the plane when the user releases the key. – Jon Jan 4 at 15:56.
You will have to go with option 1. Once you start your longer process, set a boolean of some time to indicate you are working on it and throw out other incoming identical requests. Once you complete the process set the boolean back and allow additional events.
I tried to do what you said, and set a boolean, but it didn't work. It would appear that the subsequent events are held somewhere (within Java, I don't know where), and only dispatched to me once the previous event finishes, so the events are never skipped. – Jon Jan 4 at 0:34 I assumed you were doing the long event on a separate thread.(Which might be want you need to do.) – jzd Jan 4 at 2:36 I was not, but now I am.
– Jon Jan 4 at 15:57.
I am trying to develop a pong clone, using pure Java 2D (i.e. No additional libraries) and Swing/AWT. Everything works fine for now apart from the following:When I minimize the game's frame (a JFrame and no full screen exclusive mode yet), and leave it minimized for, say, 20 minutes, after restoring the frame it looks like the JPanel inside the JFrame does not receive key events through KeyListener.
I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.