1

I have a function in my Java program that waits for the user to press the space bar. I want to modify this so that the function also will return if a certain amount of time has passed and space has still not been pressed.

I would like to keep this function as it is and not change the style, so I would really appreciate answers that are modification of this function. Thanks!

public void waitForSpace() {
        final CountDownLatch latch = new CountDownLatch(1);
        KeyEventDispatcher dispatcher = new KeyEventDispatcher() {
            public boolean dispatchKeyEvent(KeyEvent e) {
                if (e.getID() == KeyEvent.KEY_PRESSED && e.getKeyCode() == KeyEvent.VK_SPACE) {
                    latch.countDown();
                }
                return false;
            }
        };
        KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(dispatcher);
        try {
            //current thread waits here until countDown() is called (see a few lines above)
            latch.await();
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }  
        KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventDispatcher(dispatcher);
    }
nachokk
  • 14,363
  • 4
  • 24
  • 53
CodeGuy
  • 28,427
  • 76
  • 200
  • 317
  • I can't see how this would work. Swing is a single threaded environment, so if you block, waiting for user input, the EDT can't process the key event...? – MadProgrammer Jun 06 '13 at 01:42
  • 2
    [`CountDownLatch#await(long, TimeUnit)`](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.html#await%28long,%20java.util.concurrent.TimeUnit%29)? – MadProgrammer Jun 06 '13 at 01:44
  • @MadProgrammer, I've never used a CountDownLatch before so I just did some playing. If you invoke waitForSpace() from the EDT then it does not respond to the space key. If you invoke the method from a Thread, then it does respond to the space key. In both cases specifying the timeout worked. You should add your timeout suggestion as an answer. – camickr Jun 06 '13 at 01:56
  • [very similair effect, different reasons](http://stackoverflow.com/q/6121990/714968), use KeyBindings for that – mKorbel Jun 06 '13 at 06:54

2 Answers2

2

Try using CountDownLatch#await(long, TimeUnit) instead...

public void waitForSpace() {
    final CountDownLatch latch = new CountDownLatch(1);
    KeyEventDispatcher dispatcher = new KeyEventDispatcher() {
        public boolean dispatchKeyEvent(KeyEvent e) {
            if (e.getID() == KeyEvent.KEY_PRESSED && e.getKeyCode() == KeyEvent.VK_SPACE) {
                latch.countDown();
            }
            return false;
        }
    };
    KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(dispatcher);
    try {
        //current thread waits here until countDown() is called (see a few lines above)
        latch.await(30, TimeUnit.SECONDS);
    } catch (InterruptedException e1) {
        e1.printStackTrace();
    }  
    KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventDispatcher(dispatcher);
}
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
1

I believe you need to use the ExecturerService and Future to achieve this. You can set the execution time for the future to finish itself. You need to wrap your code waiting for the user input in run method of a Thread class. Once you do that and suppose you call you class as Task, then you can do this:

public class Test {
    public static void main(String[] args) throws Exception {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Future<String> future = executor.submit(new Task());

        try {
            System.out.println("Started..");
            System.out.println(future.get(5, TimeUnit.SECONDS));
            System.out.println("Finished!");
        } catch (TimeoutException e) {
            System.out.println("Terminated!");
        }

        executor.shutdownNow();
    }
}

Modify the code as per your need.

Juned Ahsan
  • 67,789
  • 12
  • 98
  • 136