Saleh Feek
Saleh Feek

Reputation: 2076

How to make some Action dependent on another Action's finish?

Action pasteAction = new DefaultEditorKit.PasteAction();

JPopupMenu popMenu = new JPopupMenu();

menuItem = new JMenuItem();
menuItem.addActionListener(pasteAction);
menuItem.addActionListener(searchAction);
menuItem.setText("Paste & Search");

popMenu menu is shown up; on mouse right click on JTextField

pasteAction is ready made.

searchAction has code to check if JTextField is empty or not. If it is not empty, then do search...

The problem is that - as I think - the pasteAction and searchAction are invoked simultaneously. So searchAction is invoked no matter pasteAction has finished its job. So when searchAction is invoked to check JTextField content; it founds it empty!

How to make searchAction dependent on pasteAction's finish?

Upvotes: 1

Views: 175

Answers (3)

camickr
camickr

Reputation: 324157

The problem is that - as I think - the pasteAction and searchAction are invoked simultaneously.

The Actions are not invoked simultaneously.

All code invoked from a listener executes on the Event Dispatch Thread (EDT). This is to make sure the code executes single threaded. This is one of the most important concept of Swing so it is important that you read the Swing tutorial on Concurrency for more information to understand this basic concept.

The problem is that the default implementation of the listener code is to invoke the listeners in the reverse order in which the listeners were added. So you could use:

menuItem.addActionListener(searchAction);
menuItem.addActionListener(pasteAction);

However, the order of listener execution is implementation specific and is not guaranteed in the Java spec. So the better approarch is to use a combined Action.

Upvotes: 3

Sergiy Medvynskyy
Sergiy Medvynskyy

Reputation: 11327

As it was proposed by AAG:

/**
 * Action which allows to execute several actions as one.
 */
@SuppressWarnings("serial")
public class CombinedAction extends AbstractAction {

    /** Holds the list of actions. */
    private Action[] actions;

    /**
     * C'tor.
     * 
     * @param someActions actions which must be executed together.
     */
    public CombinedAction(String aName, Action... someActions) {
        super(aName);
        this.actions = someActions;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void actionPerformed(ActionEvent e) {
        for (final Action a : actions) {
            a.actionPerformed(e);
        }
    }
}

Usage:

Action act = new CombinedAction("Paste and Search", pasteAction, searchAction);
menuItem = new JMenuItem(act);

Upvotes: 3

AAG
AAG

Reputation: 245

One option is to make a generic Action implementation that takes in a list of actions to take in serial. Then loop over that list, calling one at a time. Now use that new implementation and add it as the action listener.

Upvotes: 3

Related Questions