Understanding Action Properties
An Action can be passed to the constructor of a JButton or a JMenuItem, so one Action can drive several components.
One Action, Two Components
Suppose a window needs a button and a menu item that do the same job. The button sits where the user can click it directly, and the menu item sits inside a menu. You could write separate code for each, but then every change would have to be made twice. Swing offers a shorter route: an Action object. An Action can be passed to the constructor of a JButton or a JMenuItem, so one Action can drive several components.
This article follows one small program from start to finish. You will watch which object is passed where, what changes when the Action is disabled, and what changes when it is renamed. You do not need to run the program yourself to follow the discussion.
Tracing the Shared Action
- The anonymous AbstractAction is a stand-in for the Action definition the source refers to as
clearAction; the variable name and the message text are the parts to focus on. - The same
clearActionobject is passed to theJButtonconstructor and to theJMenuItemconstructor. - The final line changes the enabled state of the Action only. Neither component is named in that line.
Read the program once and focus on which object is passed where. There is one Action object, created on the line that declares clearAction. That same object is handed to the button and then to the menu item. Neither constructor copies the Action; each component is built from it. The program then calls setEnabled(false) on clearAction. Notice that this line never mentions button or item.
What the Action Holds
An Action is not just a method that runs when something is clicked. It also carries properties that describe how it should appear and whether it is available. The source names two of them directly: the NAME property, which supplies the text shown by components built from the Action, and the enabled state, which determines whether those components can be used. Because these properties live on the Action, the Action is the single place where they are stored.
This arrangement is what makes one Action useful for several components. The button and the menu item do not each hold their own copy of the name or the enabled state. They read those values from the shared Action. When the Action changes, every component built from it reflects the change.
Predicting the Effect of Disabling
What do you think happens?
After clearAction.setEnabled(false) runs, what happens to the button and the menu item?
Reveal answer
Both are disabled.
The enabled state belongs to the Action, and both components are built from that same Action. Changing the Action changes every component built from it. The line of code never names either component.
Trace the program's state step by step. Before the setEnabled call, the Action is enabled, so the button and the menu item are both available. After the call, the Action is disabled. Nothing else in the program was edited. The effect reached both components because each one reads its state from the shared Action.
Renaming the Action
Renaming works the same way as disabling. The NAME property belongs to the Action, so changing it updates the text of every component built from that Action. In the code below, the Action's NAME is changed from Clear to Reset. The surrounding program is unchanged; only the rename line differs.
clearAction.putValue(Action.NAME, "Clear");The button and the menu item both show the text Clear.
clearAction.putValue(Action.NAME, "Reset");The button and the menu item both show the text Reset.
Why You Can Drop the Component Variables
In the program above, the button and the menu item are stored in local variables named button and item. Once they have been created and added to their containers, a learner may stop keeping those variables. The source states that any later change you want to make, such as enabling, disabling, or renaming, can be done on the Action object alone. You do not need a variable that points to the button in order to disable it, because the disable request goes to the Action.
Mistakes When Managing Shared Actions
Common mistake Trying to disable the button and the menu item separately after both were built from the same Action
Why it failsThe enabled state belongs to the Action. Changing it on the Action already updates every component built from it.
Do this insteadCall setEnabled on the shared Action once, and both components will reflect the change.
Common mistake Expecting a rename to change only the button
Why it failsThe NAME property belongs to the Action, so changing it updates the text of every component built from that Action, including the menu item.
Do this insteadChange the NAME on the Action with putValue(Action.NAME, ...) and check both components.
Common mistake Assuming the variables for the components must always be kept
Why it failsLater changes to enabled state or name can be made on the Action alone, so the component variables are not needed for those changes.
Do this insteadKeep the Action in a variable you can reach, and keep component variables only when the program needs them for another purpose.
Applying the Shared Action
A program creates an Action named saveAction and passes it to both a JButton and a JMenuItem. Write the single line that changes the text shown by both components from Save to Save As, and state which components change without any other edits.
Hints
- The text shown by the components is held in the NAME property of the Action.
- Use
putValuewith Action.NAME onsaveAction, not on the button or the menu item. - Both components are built from
saveAction, so both should show the new text.
Key Takeaways
- An Action can be passed to the constructor of a
JButtonor aJMenuItem, so one Action can drive several components. - Enabling, disabling, and renaming an Action update every component built from it, because those properties belong to the Action.
- Changing the enabled state or the NAME property is done on the Action object, not on each component.
- Once the components are created, a learner does not need to keep variables that point to them to make those later changes.