2.3.2 Action
Motivation
User interfaces often require a given operation to be available from different points of access: the menubar, contextual menus, toolbars, and keyboard accelerators. An effective design choice to handle this use case is to define an Action, a pluggable entity encapsulating Command behavior and visual/UI related information, such as its icon, tooltip, keyboard accelerator, enabled status and so on.
Design
An Action is peculiar in design characteristic, combining design features of Command, Controller, and Model.
Like a Command, an Action normally provides an abstract method triggered()
to reimplement with the required behavior. Alternative strategies not
requiring subclassing allow to register a callback that is executed when the
action is triggered. Differently from a Command, the Action is more liberal in
performing UI operations, such as showing a dialog, while Commands generally
act exclusively on Models.
Actions are also both Controllers and visual Models: different Views accept the same Action and visually represent it in a different way. For example, a MenuBar might represent it as an icon followed by a title, a ToolBar might display just the icon and a tooltip, and the application as a whole might not represent it visually, but activate it when its keyboard shortcut accelerator is invoked. Information about the visual aspect of the Action are contained in the Action itself, fulfilling a Model-like role for this information.
Views supporting Actions are generally a form of visual container (e.g. Menubar, Toolbar) and provide an interface to add and remove them.
Practical Example
Qt supports a regular example of Action with the QAction class.
QAction exposes a triggered
Signal that is emitted when the Action is
activated. This Signal can then connected to any slot callback, where actual
Controller behavior takes place.
menubar = self.menuBar()
toolbar = self.addToolBar('Toolbar')
file_menu = menubar.addMenu('&File')
quit_action = QAction(QtGui.QIcon('quit.png'), '&Quit', self)
quit_action.setShortcut('Ctrl+Q')
quit_action.triggered.connect(qApp.quit)
file_menu.addAction(quit_action)
toolbar.addAction(quit_action)
In this example, we created an Action for quitting the application, then add it to both the File menu entry and the toolbar. Clicking on either entry, or using the Ctrl+Q accelerator, will invoke qApp.quit() and quit the application.