[Bryan Oakley] - 20-May-2004 An ''action'' is a pseudo-object that has properties that mostly resemble procs. In addition, actions have state and are generally associated with one or more widgets. The main advantage an action has over a proc is that it "knows" which widgets it is associated with and can enable or disable all of the widgets when the action itself becomes enabled or disabled. Bryan Schofield posted to comp.lang.tcl a nice example of one implementation of actions [http://groups.google.com/groups?th=ddf110816a167ca9]. The use of actions is also mentioned at [Tk coding styles and philosophies]. ''Bryan Schofield -- 24 May 2004'' ''Here's the source for my implementation of an action package: [ActionPackage] and [ActionPackageDemo]'' Following is a quick example of how actions can be used, using a simpler implementation than the one described by Bryan Schofield. This comes from the implementation I presently use (but is not yet publicly available). It's only 177 lines of code and is very straight-forward; I generally advise people to create their own implementation so they can appreciate how it works. button .cut -text Cut -command [list action invoke cutAction] .menubar.editMenu add command -label "Cut" -command [list action invoke cutAction] .popup add command -label "Cut" -command [list action invoke cutAction] action associcate cutAction .cut [list .menubar.editMenu "Cut"] [list .popup "Cut"] bind all [list action invoke cutAction] ... action define cutAction {} { } proc toggleSelection {} { # called whenever the selection changes if {} { action enable cutAction copyAction } else { action disable cutAction copyAction } Notice that the use of actions adds only one extra line of code in your application (the line that begins "action associate"), and is actually a net loss of several lines of code. Without actions you might have to code '''toggleSelection''' as: proc toggleSelection {} { if {} { .cut configure -state normal .menubar.editMenu entryconfigure "Cut" -state normal .popup entryconfigure "Cut" -state normal } else { ... } Not only that, but without actions you also have to add code to make sure that if there is no selection that the procedure that does the cutting won't do anything if called via the accelerator. As you can see, actions make it much easier to maintain a consistent state across all widgets that implement a particular functionality. You only have to make a single function call to disable all controls that invoke the particular action. In addition, should you add new controls (speech recognition, gestures, additional buttons or menus, etc) you do not have to hunt down all the places where you might need to enable the widgets; associate the new control with the action and the action takes care of the rest. In addition to the sheer convenience of actions, they also provide a nice API into your application, making your scripts scriptable. The scripts can be used to implement user defined macros, automated tests, or even compound actions. The above is just one sort of implementation. Many people might prefer a more object oriented approach. For example: new Action cutAction {...} cutAction button .cut -label "Cut" ... cutAction menuitem .menubar.editMenu "Cut" ... cutAction menuitem .popup "Cut" ... cutAction accelerator . No matter how actions are implemented, it's the concept that is important. Pick a style that you like and write an implementation. The first time I wrote an action library (and I'm on my 3rd or 4th iteration as I don't take code with me from employer to employer) I not only gave actions state, but I made the action definition responsible for the labels and images associated with the action. The theory was, if I wanted to change all "Cut" widgets to say "Slice" I could do "cutAction configure -label Slice" and they all would do just that. Over time I realized that most menu items and buttons don't change their text once created so I abandoned that idea and eventually whittled my personal action library down to just a handful of lines of code. ---- [NEM] ''22 May 2004'': This is a really excellent idea. Perhaps you would consider adding your code to [tklib]? I can see a common application would be to keep toolbars and menus in sync. With that in mind, would it be feasible to go one step further and have the action command actually create the toolbutton and menu item? Maybe something like: action .edit.cut -state normal -label "Cut" -underline 0 -accelerator Ctrl-C \ -command ... -image CutImg .edit.cut configure -state disabled This would actually create two widgets and a "pseudo-widget" which just forwards on requests to the actual widgets. I can see this being perhaps a bit less flexible than the above approach, though. Also, the widget path would represent the grouping of the action (i.e. the above would create a menu item in the Edit menu, and a toolbutton grouped with other Edit actions), rather than the position in the widget hierachy, so perhaps a different separator to "." would be better. Definitely a cool idea though. ---- [Category Actions] | [Category GUI]