1

I have a class extending jframe with a key binding mapped to an invisible button that does stuff. When I press the key on the keyboard, it executes the command of the button. However, if the user holds the button down, it will execute the command like a hundred times per second, crashing the program. How do I prevent this so that the command only executes... let's say... once per second when the key is pressed down?

Code snippets are as follows:

JButton fire = new JButton("");
KeyStroke spaceBar = KeyStroke.getKeyStroke("SPACE");
FireCommand fc = new FireCommand();
this.fire.setAction(fc);
imap.put(SpaceBar,"space");
amap.put("space",fc);
3
  • Do the repeated actions adhere to the system keyboard repeat rate? E.g., is there a greater delay between the initial action and the second action than there is between the rest (do the actions "speed up")? If you could change the repeat rate for just the one UI element… Commented Nov 21, 2013 at 9:53
  • Keyboard input for a game in Java may be of some help. The accepted answer includes code for setting up a repeating tasks and delays between them. Commented Nov 21, 2013 at 9:59
  • Java KeyListener keyPressed method fires too fast might be a duplicate… @aioobe (who answered Keyboard input for a game in Java) has a similar answer in that question, too. Commented Nov 21, 2013 at 10:04

3 Answers 3

1

The solution, on a Windows environment is to have two bindings. One for keyPressed which starts a Timer that continually fires at whatever interval you wish and another for a keyReleased which stops the Timer.

See the last example from Motion Using the Keyboard for a complete example.

I'm not sure if this approach still works on a Mac, because I believe the order of events on a Mac is pressed, released, pressed, released.... when you hold the key down. So the starting/stopping of the Timer may not work as expected.

Sign up to request clarification or add additional context in comments.

Comments

1

Add a variable that tracks the last time the button was pressed and add an if into your event handler that does nothing if not enough time has passed. E.g.:

// define last event time somewhere in your GUI
int lastClickTime = 0;

// min delay in milliseconds
static final int minClickDelay = 100;

// ...

// Add a check to the event handler
void onEvent(eventArgs)
{
    int now = System.currentTimeMillis();

    // do nothing, if not enough time has passed
    if (now - lastClickTime < minClickDelay) return;

    // do the real thing here
    doHardWork();
}

Comments

1

Take a look at KeyStroke#getKeyStroke(int, int, boolean), which will allow you to define a key stroke for a key release rather then key press. For example:

KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, true);

3 Comments

This is an interesting approach. It makes keyboard keys more like mouse buttons.
However, I'm not sure whether it helps the the OP, because it sounds like OP wants to be able to hold down the key, but just have (effectively) a lower repeat rate.
@JoshuaTaylor that's true, the question was a little unclear when I first read it

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.