How to Use Actions

If you have two or more components that perform the same function, consider using an Action(in the API reference documentation) object to implement the function. An Action object is an ActionListener(in the Creating a GUI with JFC/Swing trail) that provides not only action-event handling, but also centralized handling of the text, icon, and enabled state of tool bar buttons or menu items. By adding an Action to a JToolBar, JMenu, or JPopupMenu, you get the following features:

Here's an example of using an Action to create a tool-bar button and menu item that perform the same function:
Action leftAction = new <a class that implements Action>(...);
JButton button = toolBar.add(leftAction);
JMenuItem menuItem = mainMenu.add(leftAction);

For a button or menu item to get the full benefit of using an Action, you must create the component using the add(Action) method of JToolBar, JMenu, or JPopupMenu. Currently, no API beyond addActionListener(ActionListener) exists to connect an Action to an already existing component. For example, although you can add an Action object as an action listener to any button, the button won't be notified when the action is disabled.

To create an Action object, you generally create a subclass of AbstractAction(in the API reference documentation) and then instantiate it. In your subclass, you must implement the actionPerformed method to react appropriately when the action event occurs. Here's an example of creating and instantiating an AbstractAction subclass:

leftAction = new AbstractAction("Go left",
                                new ImageIcon("images/left.gif")) {
    public void actionPerformed(ActionEvent e) {
        displayResult("Action for first button/menu item", e);
    }
};

Here's a picture of a demo application that uses actions to implement three features.

A snapshot of ActionDemo, which uses actions to coordinate menus and buttons.


Try this: 
  1. Compile and run the application. The source file is ActionDemo.java(in a .java source file). You will also need three image files.
    See Getting Started with Swing if you need help compiling or running this application.
  2. Choose the top item from the left menu (Menu > Go left).
    The text area displays some text identifying both the event source and the action listener that received the event.
  3. Click the leftmost button in the tool bar.
    The text area again displays information about the event. Note that although the source of the events is different, both events were detected by the same action listener: the Action object with which the components were created.
  4. Choose the top item from the Action State menu.
    This disables the "Go left" Action object, which in turn disables its associated menu item and button.

Here is what the user sees when the "Go left" action is disabled:

A snapshot of ActionDemo when

Here's the code that disables the "Go left" action:

boolean selected = ...//true if the action should be enabled;
                      //false, otherwise
leftAction.setEnabled(selected);
After you create components using an Action, you might well need to customize them. For example, you might want to set the tool-tip text for a button. Or you might want to customize the appearance of one of the components by adding or deleting the icon or text. For example, ActionDemo.java(in a .java source file) has no icons in its menus, no text in its buttons, and tool tips for its buttons. Here's the code that accomplishes this:
button = toolBar.add(leftAction);
button.setText(""); //an icon-only button
button.setToolTipText("This is the left button");
menuItem = mainMenu.add(leftAction);
menuItem.setIcon(null); //arbitrarily chose not to use icon in menu

The Action API

The following tables list the commonly used Action constructors and methods. The API for using Action objects falls into two categories:

Creating and Using an Action
Constructor or Method Purpose
AbstractAction()
AbstractAction(String)
AbstractAction(String, Icon)
Create an Action object. Through arguments, you can specify the text and icon to be used in the components that the action controls.
void setEnabled(boolean)
boolean isEnabled()
Set or get whether the components the action controls are enabled. Invoking setEnabled(false) disables all the components that the action controls. Similarly, invoking setEnabled(true) enables the action's components.

Creating an Action-Controlled Component
Method Purpose
JMenuItem add(Action)
JMenuItem insert(Action, int)

(in JMenu and JPopupMenu)
Create a JMenuItem object and put it in the menu or popup menu. See the discussion in this section and in How to Use Menus for details.
JButton add(Action)
(in JToolBar)
Create a JButton object and put it in the tool bar. See the discussion in this section and in How to Use Tool Bars for details.

ActionDemo.java

/* Uses actions with a tool bar and a menu. */

import javax.swing.AbstractAction;
import javax.swing.Action;

import javax.swing.JToolBar;
import javax.swing.JButton;
import javax.swing.ImageIcon;

import javax.swing.JMenuItem;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JMenu;
import javax.swing.JMenuBar;

import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.JScrollPane;
import javax.swing.JPanel;

import java.awt.*;
import java.awt.event.*;

public class ActionDemo extends JFrame {
    protected JTextArea textArea;
    protected String newline = "\n";
    protected Action leftAction;
    protected Action middleAction;
    protected Action rightAction;

    public ActionDemo() {
        //Do frame stuff.
        super("ActionDemo");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //Create the toolbar and menu.
        JToolBar toolBar = new JToolBar();
        JMenu mainMenu = new JMenu("Menu");
        createActionComponents(toolBar, mainMenu);

        //Create the text area used for output.
        textArea = new JTextArea(5, 30);
        JScrollPane scrollPane = new JScrollPane(textArea);

        //Lay out the content pane.
        JPanel contentPane = new JPanel();
        contentPane.setLayout(new BorderLayout());
        contentPane.setPreferredSize(new Dimension(400, 150));
        contentPane.add(toolBar, BorderLayout.SOUTH);
        contentPane.add(scrollPane, BorderLayout.CENTER);
        setContentPane(contentPane);

        //Set up the menu bar.
        JMenuBar mb = new JMenuBar();
        mb.add(mainMenu);
        mb.add(createAbleMenu());
        setJMenuBar(mb);
    }

    protected void createActionComponents(JToolBar toolBar,
                                          JMenu mainMenu) {
        JButton button = null;
        JMenuItem menuItem = null;

        //first button and menu item
        leftAction = new AbstractAction("Go left", 
                             new ImageIcon("left.gif")) {
            public void actionPerformed(ActionEvent e) {
                displayResult("Action for first button/menu item", e);
            }
        };
        button = toolBar.add(leftAction);
        button.setText(""); //an icon-only button
        button.setToolTipText("This is the left button");
        menuItem = mainMenu.add(leftAction);
        menuItem.setIcon(null); //arbitrarily chose not to use icon in menu

        //second button and menu item
        middleAction = new AbstractAction("Do something", 
                             new ImageIcon("middle.gif")) {
            public void actionPerformed(ActionEvent e) {
                displayResult("Action for second button/menu item", e);
            }
        };
        button = toolBar.add(middleAction);
        button.setText("");
        button.setToolTipText("This is the middle button");
        menuItem = mainMenu.add(middleAction);
        menuItem.setIcon(null); //arbitrarily chose not to use icon in menu

        //third button and menu item
        rightAction = new AbstractAction("Go right", 
                             new ImageIcon("right.gif")) {
            public void actionPerformed(ActionEvent e) {
                displayResult("Action for third button/menu item", e);
            }
        };
        button = toolBar.add(rightAction);
        button.setText("");
        button.setToolTipText("This is the right button");
        menuItem = mainMenu.add(rightAction);
        menuItem.setIcon(null); //arbitrarily chose not to use icon in menu
    }

    protected JMenu createAbleMenu() {
        JMenu ableMenu = new JMenu("Action State");
        JCheckBoxMenuItem cbmi = null;

        cbmi = new JCheckBoxMenuItem("First action enabled");
        cbmi.setSelected(true);
        cbmi.addItemListener(new ItemListener() {
            public void itemStateChanged(ItemEvent e) {
                JCheckBoxMenuItem mi = (JCheckBoxMenuItem)(e.getSource());
                boolean selected =
                    (e.getStateChange() == ItemEvent.SELECTED);
                leftAction.setEnabled(selected);
            }
        });
        ableMenu.add(cbmi);

        cbmi = new JCheckBoxMenuItem("Second action enabled");
        cbmi.setSelected(true);
        cbmi.addItemListener(new ItemListener() {
            public void itemStateChanged(ItemEvent e) {
                JCheckBoxMenuItem mi = (JCheckBoxMenuItem)(e.getSource());
                boolean selected = 
                    (e.getStateChange() == ItemEvent.SELECTED);
                middleAction.setEnabled(selected);
            }
        });
        ableMenu.add(cbmi);

        cbmi = new JCheckBoxMenuItem("Third action enabled");
        cbmi.setSelected(true);
        cbmi.addItemListener(new ItemListener() {
            public void itemStateChanged(ItemEvent e) {
                JCheckBoxMenuItem mi =
                    (JCheckBoxMenuItem)(e.getSource());
                boolean selected =
                    (e.getStateChange() == ItemEvent.SELECTED);
                rightAction.setEnabled(selected);
            }
        });
        ableMenu.add(cbmi);

        return ableMenu;
    }

    protected void displayResult(String actionDescription,
                                 ActionEvent e) {
        String s = ("Action event detected by: "
                  + actionDescription 
                  + newline 
                  + "    Event source: " + e.getSource()
                  + newline);
        textArea.append(s);
    }

    public static void main(String[] args) {
        ActionDemo frame = new ActionDemo();
        frame.pack();
        frame.setVisible(true);
    }
}