Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Swing: Show pressed button when using corresponding keyboard button

I'm making a program in Java, using Swing, with a GUI that contains arrow keys. The arrow keys correspond to the arrow keys on the keyboard.

When I press the up arrow key on the keyboard, I'd like the up arrow key on the GUI to show up as being pressed. Until I release the arrow key, it should show it is still being pressed, and when released it should also release.

A snippet of my code so far (only for the Up button), which I think is totally wrong in the show being pressed category:

...
if (e.getKeyCode() == KeyEvent.VK_UP) {
                    actionArrowUp();
                    JButton buttonUp = (JButton) mainTab.getComponent(4);
                    buttonUp.setSelected(true);
                }
...
@Override
public void keyReleased(KeyEvent e) { 
            if (e.getKeyCode() == KeyEvent.VK_UP)
                actionArrowUpRelease();
                buttonUp.setSelected(true);
like image 612
Sven Avatar asked Oct 20 '12 10:10

Sven


2 Answers

Using keyBindings (as @trashgod already mentioned) is the way to go. To get the exact same visual behaviour as if activating the button by space/enter (when it were focused)

  • implement actions that delegate to the button's default actions registered for pressed/released
  • needs binding to both pressed and released of the key to simulate
  • install the binding to the buttons's parent in its inputMap of type WHEN_ANCESTOR

In code:

// the delegating  action
public static class SimulateButtonAction extends AbstractAction {

    AbstractButton button;

    public SimulateButtonAction(AbstractButton model, String fire) {
        super(fire);
        this.button = model;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        Action delegate = button.getActionMap().get(getName());
        delegate.actionPerformed(new ActionEvent(button, 
                ActionEvent.ACTION_PERFORMED, getName()));
    }

    public String getName() {
        return (String) getValue(Action.NAME);
    }

}

// example usage
JComponent content = new JPanel(new GridLayout(0, 5));
Action log = new AbstractAction() {

    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("triggered: " + ((AbstractButton) e.getSource()).getText());
    }

};
String pressed = "pressed";
String released = "released";
ActionMap actionMap = content.getActionMap();
InputMap inputMap = content.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
String[] arrows = {"UP", "DOWN", "LEFT", "RIGHT"};
for (int i = 0; i < arrows.length; i++) {
    JButton button = new JButton(log);
    button.setAction(log);
    button.setText(arrows[i]);
    content.add(button);
    // simulate pressed
    String pressedKey = pressed + arrows[i];
    inputMap.put(KeyStroke.getKeyStroke(arrows[i]), pressedKey);
    actionMap.put(pressedKey, new SimulateButtonAction(button, pressed));
    String releasedKey = released + arrows[i];
    inputMap.put(KeyStroke.getKeyStroke(released + " " +arrows[i]), releasedKey);
    actionMap.put(releasedKey, new SimulateButtonAction(button, released));
}
like image 87
kleopatra Avatar answered Nov 02 '22 23:11

kleopatra


This LinePanel uses Key Bindings and invokes doClick() in actionPerformed() to achieve an effect similar to the one you describe.

Addendum: As you want the button to appear pressed while the key is pressed, you may be able to use the optional onKeyReleased parameter of KeyStroke.getKeyStroke(). As described in ButtonModel, you'll need to make the model both armed and pressed to simulate a mouse down in the button.

like image 31
trashgod Avatar answered Nov 03 '22 01:11

trashgod