Im using a KeyAdpater
to get the events and the method addKeyListener
and works fine. The problem is that when a press the key, the action ocurrs only once and not while its being pressed, after 3-4 secs holding down the key the action occurs all the time which is what I want.
I'd want to know if there is good way to do the action all the time the key is being pressed from the very begining, not after 3-4 seconds holding down.
I thought on the next solution, but maybe there is already an implemented way to do it:
public abstract class MyKeyAdapter extends KeyAdapter{
private boolean isPressed = false;
private int pressedKey = 0;
Thread t = new Thread(new Runnable() {
@Override
public void run() {
while(isPressed)
keyPressedAction(pressedKey);
}
});
@Override
public void keyPressed(KeyEvent e) {
if(!isPressed){
pressedKey = e.getKeyCode();
t.start();
}
}
@Override
public void keyReleased(KeyEvent e) {
if(isPressed && e.getKeyCode()==pressedKey)}
isPressed = false;
}
public abstract void keyPressedAction(int key);
}
I've had good success with this by using Key Bindings, not a KeyListener, and start a Swing Timer on key press, and then stopping the Timer on Swing release. You can differentiate between the key press and release by passing the correct KeyStroke object into the bound component's InputMap using the KeyStroke.getKeyStroke(int keyCode, int modifiers, boolean onKeyRelease)
method found here: KeyStroke API. If the boolean parameter is false, the input will respond to key press, and the converse if the parameter is true.
For a quick and inelegant example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.*;
@SuppressWarnings("serial")
public class KeyBindingEg extends JPanel {
private static final String UP_KEY_PRESSED = "up key pressed";
private static final String UP_KEY_RELEASED = "up key released";
private static final int UP_TIMER_DELAY = 200;
private static final Color FLASH_COLOR = Color.red;
private Timer upTimer;
private JLabel label = new JLabel();
public KeyBindingEg() {
label.setFont(label.getFont().deriveFont(Font.BOLD, 32));
label.setOpaque(true);
add(label);
setPreferredSize(new Dimension(400, 300));
int condition = WHEN_IN_FOCUSED_WINDOW;
InputMap inputMap = getInputMap(condition);
ActionMap actionMap = getActionMap();
KeyStroke upKeyPressed = KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false);
KeyStroke upKeyReleased = KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, true);
inputMap.put(upKeyPressed, UP_KEY_PRESSED);
inputMap.put(upKeyReleased, UP_KEY_RELEASED);
actionMap.put(UP_KEY_PRESSED, new UpAction(false));
actionMap.put(UP_KEY_RELEASED, new UpAction(true));
}
private class UpAction extends AbstractAction {
private boolean onKeyRelease;
public UpAction(boolean onKeyRelease) {
this.onKeyRelease = onKeyRelease;
}
@Override
public void actionPerformed(ActionEvent evt) {
if (!onKeyRelease) {
if (upTimer != null && upTimer.isRunning()) {
return;
}
System.out.println("key pressed");
label.setText(UP_KEY_PRESSED);
upTimer = new Timer(UP_TIMER_DELAY, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Color c = label.getBackground();
if (FLASH_COLOR.equals(c)) {
label.setBackground(null);
label.setForeground(Color.black);
} else {
label.setBackground(FLASH_COLOR);
label.setForeground(Color.white);
}
}
});
upTimer.start();
} else {
System.out.println("Key released");
if (upTimer != null && upTimer.isRunning()) {
upTimer.stop();
upTimer = null;
}
label.setText("");
}
}
}
private static void createAndShowGui() {
KeyBindingEg mainPanel = new KeyBindingEg();
JFrame frame = new JFrame("KeyBindingEg");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}