2

I've registered key bindings to button and I'd like to react to all number key-strokes. I could register different event to every single key(0-9), but that's kind of stupid. So is it possible to handle it all in one event?

Here is my code that reacts only to key 0 on numpad:

  private void setKeyBindings() {
    AbstractAction aa = new AbstractAction() {
        @Override
        public void actionPerformed(ActionEvent ae) {
            System.out.println("Here");
        }
    };

    this.editButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_NUMPAD0, 0), "0");
    this.editButton.getActionMap().put("0", aa);
}

Thanks

Jan Beneš
  • 742
  • 1
  • 5
  • 24

2 Answers2

3

So is it possible to handle it all in one event?

You can create one event listener to be used by all bindings:

Maybe something like:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;

public class CalculatorPanel extends JPanel
{
    private JTextField display;

    public CalculatorPanel()
    {
        Action numberAction = new AbstractAction()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
//              display.setCaretPosition( display.getDocument().getLength() );
            System.out.println(e.getActionCommand());
                display.replaceSelection(e.getActionCommand());
            }
        };

        setLayout( new BorderLayout() );

        display = new JTextField();
        display.setEditable( false );
        display.setHorizontalAlignment(JTextField.RIGHT);
        add(display, BorderLayout.NORTH);

        JPanel buttonPanel = new JPanel();
        buttonPanel.setLayout( new GridLayout(0, 5) );
        add(buttonPanel, BorderLayout.CENTER);

        for (int i = 0; i < 10; i++)
        {
            String text = String.valueOf(i);
            JButton button = new JButton( text );
            button.addActionListener( numberAction );
            button.setBorder( new LineBorder(Color.BLACK) );
            button.setPreferredSize( new Dimension(30, 30) );
            buttonPanel.add( button );

            InputMap inputMap = buttonPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
            inputMap.put(KeyStroke.getKeyStroke(text), text);
            inputMap.put(KeyStroke.getKeyStroke("NUMPAD" + text), text);
            buttonPanel.getActionMap().put(text, numberAction);
        }
    }

    private static void createAndShowUI()
    {
        JFrame frame = new JFrame("Calculator Panel");
        frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        frame.add( new CalculatorPanel() );
        frame.pack();
        frame.setLocationRelativeTo( null );
        frame.setVisible(true);
    }

    public static void main(String[] args)
    {
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                createAndShowUI();
            }
        });
    }
}
camickr
  • 321,443
  • 19
  • 166
  • 288
  • Great answer, @camickr. Compiles as is, easy to implement. – DSlomer64 Oct 05 '15 at 21:12
  • That does assume you have a button to back the `Action` and key binding with though ;) – MadProgrammer Oct 06 '15 at 05:53
  • @MadProgrammer, you don't need the button. I changed the code to demonstrate adding the binding to the button panel. Works with or without the button added to the panel. The action command will contain the character from the keyboard. – camickr Oct 06 '15 at 14:47
2

The question you know have, is how to recognise what key stroke the action is responding to (or why the action was called)

Rather then using a single instance of an action, you could create a single special action which you could seed with the information it needs in order to do its job

public class NumberAction extends AbstractAction {
    private int number;

    public NumberAction(int number) {
        this.number = number
    }

    @Override
    public void actionPerformed(ActionEvent ae) {
        System.out.println("Here");
    }
}

Then, you would create them as you need....

private void setKeyBindings() {
    this.editButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_NUMPAD0, 0), "0");
    this.editButton.getActionMap().put("0", new NumberAction(0));
    //Other numbers...
}
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • Camickr's solution worked perfectly. However I need to do the exact same thing for F keys(F1, F2, etx.) – Jan Beneš Oct 06 '15 at 17:27
  • Camickrs solution relies on the button text to set the ActionEvent's actionCommand property, so, if you don't have a button backing the Action, then you'll need to do something like this. This approach also allows you to reuse the Action for things like JMenuItems, JButtons, JTextFields and key bindings without relying on any potential side effects – MadProgrammer Oct 06 '15 at 20:23