Understanding Action Objects in Java
You may find it useful to open another copy of this lesson in a separate browser window. That will make it easier for you to scroll back and forth among the different figures and listings while you are reading about them.
I recommend that you also study the other lessons in my extensive collection of online Java tutorials. You will find those lessons published at Gamelan.com. However, as of the date of this writing, Gamelan doesn't maintain a consolidated index of my Java tutorial lessons, and sometimes they are difficult to locate there. You will find a consolidated index at Baldwin's Java Programming Tutorials.
An Action object is an object that is instantiated from any class that implements the Action interface.
(To avoid confusion at the outset, let me point out that the Action interface is not the same as the ActionListener interface.)This leads to the obvious question, "What is the Action interface?"
Sun summarizes the purpose of the Action interface in the following way:
"The Action interface provides a useful extension to the ActionListener interface in cases where the same functionality may be accessed by several controls."A real-world example
Most text editors and word processors provide a copy action. Typically, the copy action makes it possible to highlight some text, and to copy it to the system clipboard.
The copy action can often be initiated in several ways. There will usually be a copy item on the Edit menu. Usually, there will also be a copy button on a toolbar.
(Typically also, the copy item on the menu will have an accelerator keystroke such as Ctrl+C, but that is the topic of a different article.)Need the same behavior
Regardless of whether the user initiates the copy action by selecting the menu item or by clicking the toolbar button, the behavior should be the same. (That behavior is usually to copy highlighted text onto the system clipboard.)
Copy action can be disabled
With the editor that I am using, whenever no text has been selected, the copy action is disabled. Whenever text is selected, the copy action becomes enabled. It is important that the copy item on the menu and the copy button on the toolbar become enabled and disabled in unison. (It would be very confusing if the copy menu item were to become disabled while the copy button on the toolbar remains enabled.)
In Java, the behavior of menu items and toolbar buttons is normally controlled by registering ActionListener objects on those sources, and defining the behavior in the actionPerformed method of the ActionListener object.
(If you are unfamiliar with the use of Action listeners, you will find numerous tutorial lessons that discuss the Delegation or JavaBeans event model at Baldwin's Java Programming Tutorials.)It is a straightforward matter to instantiate an ActionListener object and to register it on more than one source (a menu item and a toolbar button, for example). This will guarantee that action events will be handled in an identical way regardless of which source fires the event.
Enable and disable
It is somewhat less straightforward to guarantee that all of the sources are enabled and disabled in unison, particularly from a software maintenance viewpoint. Whenever the enabled state changes, it is necessary to individually enable or disable all of the sources on which the ActionListener object is registered.
Short of examining the source code, there is no easy way to determine how many and which sources a given ActionListener object has been registered on. You could, of course, create and maintain a list of such sources, but that would entail extra programming effort.
Action object to the rescue
This is where an Action object shines. The Action interface extends the ActionListener interface. Therefore, an Action object is an action listener, which provides a definition for the actionPerformed method.
In addition, and this is very important, the Action object is also a source of PropertyChange events. (An ordinary ActionListener object is not normally a source of PropertyChange events.)
Here is part of what Sun has to say about PropertyChange events:
"A "PropertyChange" event gets delivered whenever a bean changes a "bound" or "constrained" property. A PropertyChangeEvent object is sent as an argument to the PropertyChangeListener and VetoableChangeListener methods."What are bound and constrained properties?
If you are unfamiliar with the concept of bound properties in JavaBeans components, you will find several tutorial lessons on JavaBeans components at Baldwin's Java Programming Tutorials.
In a nutshell, a bound property is a property that will:
- Register other objects that want to be notified when the value of the property changes
- Notify them when the value changes
An Action object has a bound property, of type boolean, named enabled. Whenever an Action object is set or registered on an action-aware component, at least two important things happen.
Registered as an ActionListener object
First, the Action object is registered as an ActionListener object on the action-aware component. The behavior of the actionPerformed method, as defined in the Action object, handles Action events fired by the component.
What does action-aware mean?
An action-aware class is a class that either defines or inherits
the setAction method shown in Figure 1. An action-aware
component is an object instantiated from such a class.
|public void setAction(Action a)
Sets the Action for the ActionEvent source.
This is the method that sets up the two-way communication described earlier (and sometimes does some other things as well, which I will discuss later).
What are the action-aware components?
A review of the Java API documentation indicates that as of Java version 1.4.0, the following classes are action-aware according to the definition given above. (Note, however, not all of these classes are suitable for instantiating typical Action objects. For example, I can't think of a good reason to use a MetalScrollButton as an Action object, but there may be such a reason that I haven't thought of.)
The invocation of the setAction method on an action-aware component sets the Action property for the ActionEvent source. In other words, it establishes the behavior that will be exhibited when the action-aware component fires an Action event.
The new Action replaces any previously set Action objects.
However, it does not affect any ActionListener objects that were
independently added using the addActionListener method (I will
demonstrate this later). Also, if the Action object is already
a registered ActionListener, it is not re-registered.