Reputation: 2076
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
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
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
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