Traced Variable
Problem
Glue Code supports many-to-one interactions between components. How can one support one-to-many, and many-to-many (group-based) interactions between components?
Context
Scripted Components must be interconnected in more general configurations than the one-to-one invocations supported by the use of Glue Code.
Forces
- Components must be loosely coupled: they must rely on as few other components as possible.
- Components must be reusable: it must be possible to use them in as many situations involving as many other types of component as possible.
- Components must be interconnected, in general, in a many-to-many configuration.
Solution
Use a variable as a Broadcaster.
Parameterise components with the name of a (usually global) variable.
Components that want to receive notifications from other components
use the Tcl trace command or the Tcl_TraceVar
API functions to register write-callbacks on the variable, so that they
are informed when the variable's value has been changed. Components that
want to send notifications to multiple other components set the value
of the variable, so invoking the trace callbacks.
Consequences
One or more "announcer" components can communicate to one or more "listener" components.
A component can be an "announcer" and a "listener" at the same time by setting a trace on a variable and later setting the variable's value.
One can use a global variable to address a group of components without needing to know the exact identities of the group members.
Traced Variable often have to be global, which can make scripts hard to maintain as they grow in size.
Known Uses
The Tk toolkit uses Traced Variables to allow widgets to act
as Observers.
Many widgets have a -variable configuration option that
takes the name of a global variable which the widget must watch or update.
For example. Label, button and message widgets change their displayed text
when the value of the named variable is changed while entry widgets both
change their contents when the named variable changes and set the value
of the variable as the user edits the entry's contents.
Example Code
The following example shows how a global variable can be used to link an entry widget
and two button widgets. As the user edits the contents of the entry widget, the
button named .b updates its text label. When the user presses the button
named .clear, the global variable is set to the empty string, causing
the contents of the entry and the label of the button to be cleared.
set text_var ""
entry .e -textvariable text_var
button .b -textvariable text_var
button .clear -text "Clear" -command {set text_var ""}
pack .e .b .clear