Swing provides an implementation of the Command pattern
which helps application developer centralize functionality which
can be accessed from multiple places in the GUI. The Action
interface is used to provide a stateful ActionListener which
can provide the implementation of functionality accessed for example
from the toolbar, a menu item, and a keyboard binding. As the state of
the Action changes, for instance when it becomes disabled,
the associated controls change their state accordingly (they also become
disabled).
The Problem
For Actions to work as intended, the following connections
need to be made (assume the Action has already been created):
The control needs to be created
The Action is added as an ActionListener
on the control
A PropertyChangeListener is created which describes how
the control should be updated in response to
PropertyChangeEvents on the Action
The PropertyChangeListener is added as a listener on
the Action.
Information about the linkage may need to be retained so it can be
undone to allow garbage collection (in 1.2 this can be automatically
handled with WeakRefs).
Since a typical application may have between 5 and 25 Actions,
and 2-3 controls per Action, the steps above need to be done
up to 75 times!
In order to relieve the developer of much of this burden, we have provided
a way to have this done automatically, through helper methods on potential
Containers of Actions.
The three places where this is surfaced in Swing at present are:
JToolBar.java
public JButton add(Action a)
JMenu.java
public JMenuItem add(Action a)
JPopupMenu.java
public JMenuItem add(Action a)
The problems with this approach are several:
It is highly problematic for Builders, since it overloads
Container.add() to allow a non-Component parameter which
is not itself the thing that ends up being added.
Developers cannot participate in the configuration of the controls created
without subclassing the container classes
Even if they do subclass, the granularity of the configuration ends up being per-Container instead of per-control added.
It limits developers to the expected control for each Container
rather than allowing the full range of ActionEvent sources
which Action permits.
Solution
Many developers have commented that they would prefer to create their own
controls which are ActionEvent sources and then have a method
which connects them to a particular Action. The
solution is along these lines, and addresses the deficiencies listed above.
The added API is initially added to AbstractButton, which defines
the abstract superclass of JButton, JMenuItem, JMenu, JCheckBox,
etc.
setAction is merely a helper method which performs the linkage steps
described above as a convenience to the developer.
It is not expected that developers will often switch the
Action for a control on the fly. However, it is possible
for them to do so, using setAction since it replaces the previously
set action and fires a PropertyChangeEvent.
This does not replace the standard method of adding
ActionListeners, note that it uses
addActionListener() as stated above
The current Container apis listed above will be reimplemented
in terms of setAction, so that they give the same behavior as they did
previously. This solution will make that code much easier to maintain!
The methods configurePropertiesFromAction and
createActionPropertyChangeListener will be overridden in
subclasses to provide the expected default behavior.
createAction Factory Methods for JToolBar, JPopupMenu, JMenu
New factory methods allow one to control what toolbars
and menus create when an action is added directly, i.e. with the add
method.
This new method is needed for serialization of Abstract Actions, and gives the
developer a way to find out which keys have been set for the AbstractAction.