3

I have an Action

SampleAction a = new SampleAction("foo", null);

Then I add it to a Button, and to an ActionMap

JButton b = new JButton(a);
b.getActionMap().put("bar", a);
b.getInputMap().put(KeyStroke.getKeyStroke("F1"), "bar");

I put a trace (System.out.println("Action [" + e.getActionCommand() + "] performed!");) inside the Action. When I press the button with mouse it shows

Action [foo] performed!

But when i use F1, it shows:

Action [null] performed!

Why?


class SampleAction extends AbstractAction
{
    public SampleAction(String text, Icon icon) {
        super(text, icon);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("Action [" + e.getActionCommand() + "] performed!");
    }
}
David Kroukamp
  • 36,155
  • 13
  • 81
  • 138
Fabricio
  • 7,705
  • 9
  • 52
  • 87
  • Can we see the `SimpleAction` class, posting an [SSCCE](http://sscce.org) – David Kroukamp Dec 06 '12 at 10:21
  • 1
    @DavidKroukamp there you go – Fabricio Dec 06 '12 at 10:30
  • why questions are hard to answer (can't see into the brains of the swing team devs, not even in the presence, far less in the past :-) If an Action doesn't have its actionCommmand explicitly set, it defaults to SomeThing. That SomeThing is different at the two locations (in AbstractButton.fireActionEvent vs. SwingUtilities.notifyAction) where the actionEvent is created. – kleopatra Dec 06 '12 at 10:34

2 Answers2

3

Unless I am misunderstanding You should call getActionCommand on the instance of your JButton via ae.getSource() where as you are calling getActionCommand() on the ActionEvent:

  SampleAction a = new SampleAction("foo", null);

  JButton b = new JButton(a);
  b.getActionMap().put("bar", a);
  b.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("F1"), "bar");

class SampleAction extends AbstractAction
{
    public SampleAction(String text, Icon icon) {
    super(text, icon);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
    System.out.println("Action [" + ((JButton)e.getSource()).getActionCommand() + "] performed!");
    }
}

UPDATE:

Thanks to @Kleopatra this might be a better way:

SampleAction a = new SampleAction("foo", null);

JButton b = new JButton(a);
b.getActionMap().put("bar", a);
b.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("F1"), "bar");

 class SampleAction extends AbstractAction {

        public SampleAction(String text, Icon icon) {
            super(text, icon);

            putValue(Action.ACTION_COMMAND_KEY, text);//'foo' will be printed when button clicekd/F1 pressed
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            System.out.println("Action [" + e.getActionCommand() + "] performed!");
        }
    }
David Kroukamp
  • 36,155
  • 13
  • 81
  • 138
  • hmm ... that's not really answering the question (as I perceive it, anyway :-) - it's more about the difference of the _actionCommand_ when the same Action is used as the buttons (that is performed on clicking) vs. used in the actionMap. – kleopatra Dec 06 '12 at 10:29
  • I put `JComponent.WHEN_IN_FOCUSED_WINDOW` but it is still printing `null` when pressing F1 – Fabricio Dec 06 '12 at 10:30
  • 1
    oh now it is `:P` I just thought I was doing something wrong with the keybinding. `:)` But then it seems ok. – Fabricio Dec 06 '12 at 10:39
  • 1
    question transmorphed - and ... again one of those _don't_, I'm afraid :-) A button's internal default creation of the actionCommand is an undocumented implementation detail (and not the cleverest thingy to do in itself: names might be localized and change - not a good candidate for an identifier) - application code which needs the command _must not_ rely on such a windy property. Instead, set it on the _action_ Plus, it defeats the whole purpose of the Action: it's designed to be used independently of the view (could be a JTextField f.i. or anything else) – kleopatra Dec 06 '12 at 10:47
  • @kleopatra the only other solution I know of would be than to use a mnemonic but that will force the use of ALT+Key seqeunce – David Kroukamp Dec 06 '12 at 11:03
  • 1
    hmm ... what's wrong with myAction.putValue(Action.ACTION_COMMAND_KEY, "fooCommand")? – kleopatra Dec 06 '12 at 11:05
1

I have no access to your SampleAction, but I guess the "foo" text you pass in the constructor is used as a text and has nothing to do with the action command.

If you look into the AbstractButton class from which JButton extends, you see

public String getActionCommand() {
    String ac = getModel().getActionCommand();
    if(ac == null) {
        ac = getText();
    }
    return ac;
}

This method is used when creating the ActionEvent which is passed to the action. When you click the button, this method is called and I assume ac is null but the getText() method returns the "foo" you used in your SampleAction class.

When you trigger the action directly by pressing F1, you bypass this mechanism and simply trigger the action. If you want to avoid this, you can add an Action to the ActionMap of the JButton which simply does JButton#doClick, which is the API call to perform a "click" on the button

Robin
  • 36,233
  • 5
  • 47
  • 99
  • Oh so that's not important. I just thought I was doing something wrong with the keybinding. :) – Fabricio Dec 06 '12 at 10:36
  • 1
    the "however..." is a bit misleading: nothing by-passed, just the ActionEvent created at a different location, see SwingUtilities.notifyAction :) Defaults are just ... defaults, and uncontrollable (and here even undocumented). If we need to control them, the only way out is to configure the action with it. – kleopatra Dec 06 '12 at 10:39