Understanding Action Objects in Java
The Action interface
According to Sun,
"The Action interface provides a useful extension to the ActionListener interface in cases where the same functionality may be accessed by several controls."Previous sections in this article have discussed how such a capability may be used.
Here is a quotation from John Zukowski, which may help to illuminate the purpose of the Action interface.
"The Action interface is an extension to the ActionListener interface that's very flexible for defining shared event handlers independent of the components that act as the triggering agents. ..., the interface implements ActionListener and defines a lookup table data structure whose keys act as bound properties. Then, when an Action is associated with a component, these display properties are automatically carried over to it."The actionPerformed method and other things
Because the Action interface extends the ActionListener interface, it declares the actionPerformed method. In addition, this interface makes it possible to define the following items in a single location:
- Text strings that describe the properties of action-aware components associated with an Action object.
- Icons that may be displayed on action-aware components associated with an Action object.
- The enabled/disabled state that should be tracked by action-aware components registered as PropertyChange listeners on an Action object
In addition to the actionPerformed method inherited from the ActionListener interface, the Action interface declares six methods in support of the functionality described above.
The two methods shown in Figure 7 are the standard JavaBeans setter
and getter methods for the enabled property.
|isEnabled() - Returns the enabled state of the Action.
setEnabled(boolean b) - Sets the enabled state of the Action.
Although it isn't obvious in the method declarations, the enabled property is a bound property as described earlier in this article. (In fact, the word bound doesn't appear anywhere in the JavaDocs description of javax.swing Interface Action for Java 2 Platform SE v1.4.0.)
The two methods shown in Figure 8 are the standard JavaBeans methods
for registering and unregistering a PropertyChangeListener object.
|addPropertyChangeListener(PropertyChangeListener listener) -
Adds a PropertyChange listener.
removePropertyChangeListener(PropertyChangeListener listener)- Removes a PropertyChange listener.
All objects that are registered as a PropertyChangeListener on the Action object are notified when the value of any bound property changes.
The two methods shown in Figure 9 are used to put and get
the values of properties that I will refer to as keyed properties.
These methods behave like typical put and get methods for
a hashtable object.
|void putValue(String key, Object value) - Sets one of this object's
properties using the associated key.
Object getValue(String key) - Gets one of this object's properties using the associated key.
The values of these properties consist of:
- Text strings that describe the properties of action-aware components associated with an Action object
- References to ImageIcon objects that may be displayed on action-aware components associated with an Action object.
The keys associated with these values are declared by the Action interface as public static final fields of type String, having the following names and purposes.
- NAME - Used for storing the name for the action. Appears at text on the face of a tool bar button or a menu item.
- SHORT_DESCRIPTION - Used for storing a short description for the action. This description is used for tooltip text.
- SMALL_ICON - Used for storing a small icon for the action. This icon appears on toolbar buttons and menu items.
- ACCELERATOR_KEY - Used for storing a KeyStroke to be used as the accelerator for the action.
- MNEMONIC_KEY - Used for storing a key code used as the mnemonic for the action.
- ACTION_COMMAND_KEY - Used to determine the command string for an ActionEvent object.
- DEFAULT - Can be used as the storage-retrieval key when setting or getting one of this object's properties.
- LONG_DESCRIPTION - Used for storing a longer description for the action.
Because these fields are declared in an interface, they are inherently final. They are all references to String objects. Although the documentation doesn't specify the values encapsulated in the String objects, it can be determined experimentally that as of version 1.4.0, the string values encapsulated in the String objects are:
The values associated with these keys (in a key-value pair sense) in any particular program are dependent on the program. You will see how some of these keys are used in the sample program to be discussed later, so I won't discuss them further at this time.
Keyed properties are bound properties
Apparently each of these keyed properties behaves like a bound property; meaning that all registered PropertyChangeListener objects are notified whenever the value of one of these properties changes. Whether or not that listener object takes any specific action as a result of the change is determined by the author of the class from which the PropertyChangeListener object is instantiated.
Implementing the Action interface
As is usually the case, you can start from scratch and define a new class that implements the Action interface. Among other things, this will require you to provide PropertyChange support.
If you elect to take this route, I recommend that you consider using an object instantiated from the PropertyChangeSupport class or the SwingPropertyChangeSupport class to handle the registration and notification of PropertyChangeListener objects.
However, in most cases, you won't need to start from scratch. Rather, you can define a new class that extends the AbstractAction class, and override any methods whose behavior needs to be different from that defined in that class.
The AbstractAction class
According to Sun,
"This class provides default implementations for the JFC Action interface. Standard behaviors like the get and set methods for Action object properties (icon, text, and enabled) are defined here. The developer need only subclass this abstract class and define the actionPerformed method."Often, by extending this class, instead of defining a new class that implements the Action interface, you can save yourself a lot of programming effort.
(As a side note regarding the importance of the Action interface, more than two-dozen classes in v1.4.0 extend the AbstractAction class.)Fields of AbstractAction class
In addition to the final fields inherited from the Action interface, this class defines the following two fields:
- SwingPropertyChangeSupport changeSupport
- boolean enabled
The second field is of type boolean, and specifies whether the action is enabled at a particular point in time. The default value is true.
Methods of AbstractAction class
The AbstractAction class provides default implementations for each of the six methods declared in the Action interface (See Figures 7, 8, and 9.)
In addition, the AbstractAction class defines the four methods
shown in Figure 10.
|clone() - Clones the abstract action.
firePropertyChange(String propertyName, Object oldValue, Object newValue) - Supports reporting bound property changes.
getKeys() - Returns an array of Objects which are keys for which values have been set for this AbstractAction, or null if no keys have values set.
getPropertyChangeListeners() - Returns an array of all the PropertyChangeListeners added to this AbstractAction with addPropertyChangeListener().
The behavior of the clone method should be self-explanatory.
This method can be used in a subclass to fire a PropertyChange
event. When a PropertyChange event is fired, the SwingPropertyChangeSupport
object will send the appropriate PropertyChangeEvent to all registered
Page 3 of 6