################################################################################ # Wattr extension for Tcl/Tk 8.xx (and WTK, a Window Tk3.6 port) # ################################################################################ 1. Basic usage ============================================================================= Wattr is primarily used as an extension to glue additional attributes to a Tk widget. The usual method for linking attributes (i.e. variables) to a Tk widget is to use an array variable. The name of the array is derived from the widget's name. proc set_foo_of { w value } { upvar #0 attr$w a set a(foo) $value } proc get_foo_of { w } { upvar #0 attr$w a set a(foo) } To be sure that the array is deleted when the widget is destroyed, the Tcl/Tk programmer has to define an artificial Destroy binding and include it in the widget's bindtags list. bind AttrDestroy { unset attr%W } ... bindtags $w [concat [bindtags $w] AttrDestroy] I was getting sick doing this kind of stuff. Every procedure that needs access to an attribute needs to have this "upvar" line. The sample from above using the Wattr extension would look like this: package require Wattr ... proc set_foo_of { w value } { wattr configure $w foo $value } proc get_foo_of { w } { wattr cget $w foo } There is no need for "bindtags" or artificial "Destroy" bindings because it's all done internally. Wattr is very simple to learn and to use. These basics could also be done in pure Tcl, but for performance reasons and for additional features, Wattr was written in C. 1.1 Detailed description of the basic subcommands: -------------------------------------------------- wattr configure ?attr_name? ?optionvalue? ... This works much like the "configure" subcommand Tk widgets. If only the widgetname is given, "configure" prints a list of the widget's current attributes. Sample 1: % frame .foo .foo % wattr configure .foo bar 5 foo 6 bar foo % wattr configure .foo -minusoption 123 -minusoption % wattr configure .foo {-minusoption {} 123} {foo {} 6} {bar {} 5} In the list of a single attribute, first the name appears, then the default value (more on default values later) and finally the current value. It is not important if the attribute has a minus sign or not, you can use whichever method you prefer. The difference to the Tk core "configure" command is that a "wattr configure" returns a list of options which were changed during the configure call. This allows additional actions to be performed if a certain attribute was changed. Sample 2: % set changed [eval wattr configure $w $args] -width -height -color % if {[wattr changed [list -height -width] $changed]} { manage_geo $w } "wattr changed" returns information if -width or -height was changed by the previous configure call. If neither "-width" or "-height" were in the listvariable "changed", "wattr changed" returns 0. wattr cget attr_name ?result_variable? works much like the "cget" subcommand of Tk widgets. It returns the current value of an attribute. If "result_variable" is used, the extension writes or creates this variable with the result of the subcommand. This deviates a bit from the Tk "cget" semantics, but is very useful. WARNING! If the attribute doesn't exist for this widget, no error is thrown, but the empty value is returned. It turned out that this relaxed error handling was much more usable in our scripts. If one really needs to know that the attribute has to exist in a certain place, use "wattr exist $w " Sample 3: % wattr cget .foo bar 5 % if {[wattr cget .foo foo result]==6} { puts "result is $result" } result is 6 % if {[wattr cget .foo abc result]==""} { puts "result is empty" } result is empty % wattr exist .foo foo 1 % wattr exist .foo abc 0 wattr cinfo ?attr_name? prints loads of informations as a list of lists about all current attributes when no name is given as the 3rd argument. If "attr_name" contains a valid attribute identifier, all information about this particular attribute is printed in listform. Sample: % wattr configure .foo -abc 1 -def 2 -abc -def 2. Descriptions, changeprocs, variable names, default values and aliases ============================================================================ 2.1 Descriptions ----------------- To have a single place to describe all attributes of a certain widget type and to have default values for the attributes, there is the possibility to write a description. Descriptions are fixed to Tk class names. You write a description for a specific Tk class, and when wattr tries to access a widget for the first time it looks for a description in the Tk class for the widget and fills in the default values. The "-name" option inside a list for each attribute is required. Sample 4: % wattr description create Foo \ [list -name "attr1" -default def1] \ [list -name "attr2" -default def2] ... % frame .foo -class Foo .foo #during this configure the description is searched and the default values # are filled in % wattr configure .foo {attr1 def1 def1} {attr2 def2 def2} Descriptions are much more powerful than just setting default values. There are some other interesting options: -type int|pixels|double|string|color|anchor|justify|cursor| state_nda|state_nd|state_na|side (state_nda denotes a state parameter with the possible values of "normal" "disabled" "active", state_nd is a state parameter with the possible values of "normal" and "disabled", state_na is either "normal" or "active" ) Instructs wattr to validate the type during "configure" actions. default is "string" This also prevents manual type checking inside the changeproc. -usevar 0|1 Usually the wattr extension creates internal list structures to store the values and names of the attributes. However, in some cases, it might be desireable to be able to pass a certain attribute as a variable name to Tk widgets, for example as parameter to "-textvar" for a Tk entry. "-usevar" instructs Wattr to create a namespace variable for this attribute. This is useful in conjunction with the "varname" and "alias" subcommands. Default is 0. The variable is created inside of the "Wattr" namespace in an array which is named after the widget the attribute belongs to. Sample 5: % wattr description create Foo \ [list -name "-attr1" -default def1 -usevar 1] \ [list -name "-attr2" -default def2 -usevar 1] \ [list -name "-attr3" -default def3 ] % frame .foo -class Foo .foo % wattr cget .foo -attr1 def1 % parray ::Wattr::.foo ::Wattr::.foo(-attr1) = def1 ::Wattr::.foo(-attr2) = def2 % set vname [wattr varname .foo -attr1] ::Wattr::.foo(-attr1) % entry .e -textvar $vname -changeproc Whenever the attribute is changed, the given tcl-procedure is called. The arguments of the procedure must adhere a certain scheme. The arguments are proc changeproc { w name old new } #w is the widget name #name is the name of the attribute #old is the previous value of the attribute and #new is the current value -optionname When wattr applies the description to a widget, it looks first in the option database to find a default value for the attribute. Default optionname is the attribute name without a leading minus sign. Sample 6: % wattr description create Foo \ [list -name "-attributetest" ] \ [list -name "-attributetest2" -optionname "attributeTest2" ] % option add *Foo.attributetest "abc" % option add *Foo.attributeTest2 "def" % frame .foo -class Foo .foo % wattr cget .foo -attributetest abc % wattr cget .foo -attributetest2 def -optionclass Allows the optiondatabase class for the attribute to be set. Will be used in the internal Tk_GetOption call (aka "option get") and will appear in the configure list of a "subclassed" megawidget. The following flags are used only in conjunction with the "wattr subclass". They are covered in detail later on. -propagate Propagates configure options to child widgets. -usepropagatedefault <0|1> Use the default value of the child widget if the option is propagated to a child widget and neither the -default option nor something in the option databae is configured for this widget type. Default is 1. -private <0|1> The option will not appear in the configure list of a subclassed widget if -private is set to 0. Default is 1. 2.2 changeproc --------------- The changeprocs are fired when a "configure" operation is completed changing all of the attributes. All the changed attributes already have their new values when the first changeproc is fired. Changeprocs are intented to help in the building of megawidgets, but may also serve as a debugging aid (like a variable trace) and enable the Tcl programmer to refuse certain values. If the changeprocs fails (throws an error), the "configure" operation fails and the attribute value is reset to the original value. If the changeproc returns with "return -code break", the old value is restored. This implements a read-only behaviour. To prevent infinite recursion, it is not possible to set an attribute inside the changeproc. 2.3 variable names of wattr attributes ---------------------------------------------- wattr varname Returns the name of a tcl-variable, which is linked to the attribute as shown in Sample 5. If the attribute came from a description and was declared with -usevar 1, the attribute values are initially created as tcl-variables, otherwise they are created in internally-linked lists. If the "varname" subcommand is invoked and an attribute is still in its internal list representation, it will be converted to a variable representation and never switched back. The namimg scheme for the variables is simple: The variable are created inside the ::Wattr namespace. There is 1 array variable per widget and it has the same name as the widget. 1 attribute corresponds to 1 array entry, the name of the entry is the same as the attribute name. Sample 7: % frame .foo .foo % wattr configure .foo -abc 1 -abc % set vname [wattr varname .foo -abc] ::Wattr::.foo(-abc) % set $vname 5 5 % wattr cget .foo -abc 5 2.4 variable aliases and arraymaps ---------------------------------------------- wattr alias Links the wattr attribute of a widget to a (local) variable. Modifying the variable also modifies the wattr attribute value and vice versa. Internally this is done with an "upvar" call, which is why the internal respresentation of the wattr attribute is switched from a linked list element to a variable representation like in a call to wattr "varname". wattr arraymap Links a given array variable to the attributes of a certain widget. Sample 8: % frame .foo .foo % wattr configure .foo -bar 1 -goo 3 -text hallo -bar -goo -text % wattr arraymap .foo abc % parray abc abc(-bar) = 1 abc(-goo) = 3 abc(-text) = hallo These subcommands allow use of "append" "lappend" "incr" and other commands, which expect a variable name as argument. Sample 9: we want to store a list as an wattr argument, and append a new element % wattr configure .foo -intlist [list 2 4 5 6] -intlist % wattr alias .foo -intlist ilist % lappend ilist 9 2 4 5 6 9 % wattr cget .foo -intlist 2 4 5 6 9 3. Megawidgeting with wattr ============================================================================ 3.1 "lighweight" megawidgeting with "wattr subclass" ---------------------------------------------------------------------------- The idea behind this was merging wattr and core configure options of a widget into a single configuration string and letting it appear as single core widget. I call this "lightweight" megawidgeting - just glueing an additional option to the widget and let it behave like the original one. If the additional option is configured, a changeproc can be called. All other options are passed through to the original widget. Internally this is done by renaming the original Tcl_Command of the widget and creating a new Tcl_Command, which then handles the configure/cget subcommands and passes all other commands to the original widget. The key to wattr megawidgeting is "wattr subclass". "wattr subclass" renames the original widget and installs it's own C-CommandProc to handle the subcommands. Sample 10: wattr description create ValueListbox \ [list -name "-value" -default "" -changeproc vl_change ] proc vl_change { w attr old new } { $w delete 0 end eval $w insert 0 $new } proc vlistbox { w args } { listbox $w wattr subclass $w -passthrough . -descriptionclass ValueListbox $w cinit $args return $w } % vlistbox .l -value [list 1 2 3 4 5] .l % .l configure -background red % .l cget -foreground black This very short sample implements a listbox which has an additional configure option "-value" to be able to configure the contents of the listbox. All other options like "-background" are passed through to the original listbox. This is controled by the "-passthrough ." flag of "wattr subclass" "passthrough ." means that all non-wattr declared options are passed to the original widget, and that all subcommands except "configure" and "cget" are passed to the original widget. "passthrough" also accepts paths to subwidgets, Imagine a listbox, which is gridded inside a frame together with 2 scrollbars to implement a scrolled listbox. It is very likely that this simple option will be extended a bit, to have a more fine grained control about what is passed to the original widget. At the moment it is possible to define a "-cmdproc" during "wattr subclass", which overrides the "passthrough" option and all subcommands appear in the tcl-procedure which is passed as argument to "-cmdproc" Sample 11: proc se_proc { w this subcomm args } { if {$subcomm=="set"} { $w delete 0 end $w insert 0 [lindex $args 0] } else { eval $this $subcomm $args } } proc setentry { w args } { entry $w wattr subclass $w -passthrough 1 -cmdproc se_proc $w cinit $args return $w } % setentry .e % .e set 5 % .e get 5 In this sample there was defined a cmdproc, "se_proc", which handles all subcommands of the "setentry". If the subcommand was "set", the necessary actions are done to fill the entry (note this isn't perfect because it will not work for the entry state "disabled"). The options are passed to the original entry like in Sample 10. The default descriptionclass is the [winfo class $w]. However, it is possible to instruct "wattr subclass" to use another descriptionclass with the "-descriptionclass" option. 3.1.1 "wattr subclass" options ----------------------------------------------------------------------------- -descriptionclass Instructs "wattr subclass" to apply the specified descriptionclass if the subclassed command first calls a "configure", "cget" or "cinit" operation. Default is the widget class of the "subclass'ed" widget. This also allows a widget to be subclassed twice with different descriptions (each attribute also has a pointer to its description) -class Sets the optionclass for the widget. Default is the widget class of the "subclass'ed" widget. This is used when finding the default values for the widget - "wattr" will look in the option database under this class. -passthrough Controls to which subwidget the subcommands are passed if no "-cmdproc" option is set, or if no command exists and "-cmdprefix" is set. Preferred use for lightweight megqwidgeting. accept the same arguments as the "-propagate" option for descriptions without matchPatterns. -deferchangeprocs <0|1> By default, the firing of all pending changeprocs are deferred until the first "cinit" call of the megawidget. If this option is set to 0, the first "wattr cget/configure $megawidget" call invokes pending changeprocs. -allowruntimeattributes <0|1> Default is 0. Usually if you try to configure an option which does not exist, you will get an error. However, if you set this option to 1, configuring an unknown attribute will create a new one and you can invoke "cget" operations later to retrieve the value. (Note, with "wattr configure $w -newattribute foo" you can always append new attributes to the widget) -widgetprefix Empty by default The original widgetcommand is by default renamed to ::Wattr:: For example ".f" is renamed to "::Wattr::.f@" -widgetsuffix "@" by default The following options are explained in detail later on because they allow fine-grained control of the handling of the megawidget's subcommands. -cmdproc Specifies a single procedure to handle subcommands. -cmdprefix Specifies a prefix for procedures, which handle each subcommand in the form ${cmdprefix}${subcommand} This overrides the -cmdproc option. If a procedure doesn't exists for the specified subcommand and the "-passthrough" option is set, the subcommand will be handeled by the subclass'ed widget. If no "-passthrough" is set, ${cmdprefix}DEFAULT will be called. -cmdlist (currently not implemented) Handles subcommands with the help of commandlists which were created in a previous call to "wattr cmdlist create". All subcommands found in this list are handled either in the procedure specified in the "-proc" argument for this subcommand or the "-passthrough" option for this subcommand when set. If neither a -proc nor a -passthrough option was set, either the above -cmdprefix or the -cmdproc option is inspected to find a proc handling the subcommand. 3.1.2 usage of "cinit" ----------------------------------------------------------------------------- The "cinit" subcommand of the widget was developed to prevent the "eval configure $w $args" line. In the "cinit" call the "wattr" structures for the suitable decriptionclass are initialized. If a widget is "subclassed", all changeprocs are delayed until the first "cinit" call. This prevents the firing of the changeprocs if a simple "wattr cget" operation is invoked before the complete megawidget is built. That's why a megawidget implementor is forced to use "cinit",otherwise the changeprocs never will be fired. 3.2 wattr real megawidgeting ---------------------------------------------------------------------------- The term "real megawidgeting" means building a Tk widget in tcl composed of various core widgets with the help from "wattr" and letting it behave like a Tk core widget. This includes things such as symbolic names for subwidgets, option propagating, option abbreviations, and management of subwindows. 3.2.1 symbolic names for subwidgets (_chxxx subcommands) ---------------------------------------------------------------------------- By diving into several megawidget packages I discovered that the majority of the implementors like to have clear symbolic names for their subwidgets. For example, Brian Oakley in his widespread combobox uses "$widgets(entry)" and "$widgets(button)" instead of real pathNames. This allows for the changing of the pathNames of the subwidgets without too much hassle. "wattr" has builtin support for this. If a megawidget is created using "wattr subclass", the widget also gets a bunch of subcommands to manage symbolic names with the prefix "_ch" (_child) : _chadd gives a subwidget a symbolic name _chget returns the Tk pathname for the symbolic name _chinfo prints out a complete list of the subwidgets _chmap maps the symbolic names of the megawidget to an array variable to allow the same programming style as described above _chgethook returns the name of the widget command which was renamed by "wattr subclass", normally ::Wattr::@ , this is controlable by the "-prefix" and "-suffix" option of "wattr subclass" Sample 12: % frame .foo .foo % wattr subclass .foo -passthrough 1 .foo % pack [entry .foo.e ] -side left % .foo _chadd .foo.e Entry % .foo _chget Entry .foo.e % pack [button .foo.b -image arr_down ] -side right % .foo _chadd .foo.b Button % .foo _chget Button .foo.b % .foo _chinfo Button Entry THIS % .foo _chmap widget widget(Button) = .foo.b widget(Entry) = .foo.e widget(THIS) = .foo % .foo _chgethook ::Wattr::.foo@ 3.2.2 option propagation ("-propagate" option for descriptions) ---------------------------------------------------------------------------- Suppose we want to implement a listbox-like widget by using a bunch of gridded entries inside a frame . The number of entries is controlled by a "-height" attribute. All entries should change the background if we set the background of the megawidget. We could do this inside the changeproc of the "-background" attribute. Sample 13 (entrylb.tcl): wattr description create EntryList \ [list -name -background -abbreviation -bg -changeproc change_bg \ -default white -type color] \ [list -name -height -changeproc change_height -default 0 -type pixels] proc change_height { w name old new } { for { set i 0} {$i<$new} {incr i} { if {![winfo exists $w.e$i]} { grid [entry $w.e$i] -col 0 -row $i } } # remove unneeded entries while {[winfo exists $w.e$i]} { destroy $w.e$i incr i } change_bg $w -background "" [wattr cget $w -bg] } proc change_bg { w name old new } { for { set i 0 } {$i<[wattr cget $w -height]} {incr i} { if {[winfo exists $w.e$i]} { $w.e$i co -bg $new } } } proc entrylistbox { w args } { frame $w -class EntryList wattr subclass $w -descriptionclass EntryList $w cinit $args return $w } destroy .lb pack [entrylistbox .lb -height 5] .lb configure -bg red Note that we need to also change the background if we change the height (otherwise the freshly created entry widgets don't get the background if we change "-height" at runtime). For a real widget we have additional attributes like foreground, selectbackground etc., which we also would have to propagate in "change_height". We would have to call change_foreground,change_selectbackground... which is tedious, boring, and leads to code duplication (and in the case that the subwidgets don't exist in the creation case, is very annoying. Note the [winfo exists ..] line in "change_bg", this also depends on the order of the wattr classdescription.) But the "wattr" extension has an automatic feature, a simple "-propagate" entry in the classdescription which eliminates the need for "change_bg". Sample 13 rewritten using "-propagate" Sample 14 (entrylb.tcl): wattr description create EntryList2 \ [list -name -background -abbreviation -bg \ -default white -type color -propagate [list . .e*] ] \ [list -name -height -changeproc change_height -default 0 -type pixels] proc change_height { w name old new } { for { set i 0} {$i<$new} {incr i} { if {![winfo exists $w.e$i]} { grid [entry $w.e$i] -col 0 -row $i } } # remove unneeded entries while {[winfo exists $w.e$i]} { destroy $w.e$i incr i } # instead of manually propagating all possible options, we call "wattr propagate" wattr propagate $w all } # change_height is the same as in the previous sample proc entrylistbox2 { w args } { frame $w -class EntryList2 wattr subclass $w -descriptionclass EntryList2 $w cinit $args return $w } destroy .lb2 pack [entrylistbox2 .lb2 -height 5] .lb2 configure -bg green The "-propagate [list . .e*]" entry means that the background is propagated to the container frame and to widgets which match the .e* globbing pattern. The "." in ".e*" denotes the root widget of the megawidget (the frame). 3.2.3 "-propagate" in detail ---------------------------------------------------------------------------- "-propagate" accepts a list of patterns and performs the neccessary "configure" calls to the subwidgets. If the "configure" calls to subwidgets fail, you will get an error in the megawidget "configure" call. An entry in the pattern list may have different formats and there are also special entries. The general form is: ?:otheroptionname? is a matchpattern as described below. "otheroptionname" allows the attribute in the megawidget to be named differently than the configure attribute in the children. For example: -name -entrybackground -propagate ".e*:-background" or -name -entryborderwidth -propagate ".e*:-borderwidth" Valid entries for ____________________________ "ALL" means that all subwidgets, including the megawidget itself, will get the attribute propagated, We could also use that for sample 12. "THIS" is synonym for "." and referes to the subclassed widget. like "." ".e*" ".l.w" like "Button" or "Entry*" Default values for the propagated attributes -------------------------------------------- If an Attribute has no "-default" option in the class description, the default value of the first widget the attribute is propagated to is taken (controlable by the list order). This is what we want in most cases. If we have an entry widget inside the megawidget and want to expose the "-font" property to the megawidget, we want it to get its platform specific default value upon creation. Only if the "-default" option in the class description is set, this value is used as the default value. 3.3 Handling subcommands, command procs (-cmdproc , -cmdprefix , -cmdlist options of "subclass") ------------------------------------------------------------------------------- All procedures handling widget subcommands have the same number of arguments. The first argument is the widgetpath of the megawidget, 2nd is the subcommand and the rest are contained in "args" (which may be empty in case the subcommand has no further arguments) proc cmdproc { w subcommand args } { } 3.3.1 -cmdproc --------------- If only the "-cmdproc cmdproc" argument is given, "cmdproc" would handle all subcommands of the widget, even if a -passthrough option was set in "wattr subclass". If subcommands should be passed to subwidgets, it must be done in "cmdproc". switch $subcommand { ... "insert" { eval [$w _chget Entry] $subcommand $args } ... } 3.3.2 -cmdprefix ----------------- Defines a prefix which is used as the base for describing a proc for each subcommand. Sample 15 (scrolledlb.tcl): proc scrolledbox {w args} { ... frame $w listbox $w.lb wattr subclass $w -passthrough .lb \ -cmdprefix "::ScrolledListbox::cmd_" ... } proc ::ScrolledListbox::cmd_delete { w subcomm args } { eval $w.lb $subcomm $args check_scrollbars $w cmd_delete } proc ::ScrolledListbox::cmd_insert { w subcomm args } { eval $w.lb $subcomm $args check_scrollbars $w cmd_insert } pack [scrolledbox .f ] -expand 1 -fill both If we would type % .f insert 0 1 2 3 "::ScrolledListbox::cmd_delete .f insert 0 1 2 3" would be called. If we would type % .f xview wattr tries to find a proc "::ScrolledListbox::cmd_xview", but there isn't one, but the "-passthrough .lb" option was set, so the subcommand is directly passed through to the listbox. In the case that the -passthrough option was not set, wattr would try to call "::ScrolledListbox::cmd_DEFAULT" to allow the user to give back an appropriate error. If a "-cmdprefix" option is set, the "-cmdproc" option will be completely ignored. 3.3.2 -cmdlist (currently not implemented) --------------------------------------- The -cmdlist option provides a very fine grained control for handling each subcommand and helps to perform some common tasks such as checking the number of arguments and giving back an appropriate error message if the number of arguments is not correct. wattr cmdlist create ScrolledListbox \ {-cmd "delete" -minargs 1 -maxargs 2 -help " ?endindex?" \ -proc ::ScrolledListbox::delete } \ {-cmd "insert" -minargs 1 -help " arg ?arg?" \ -proc ::ScrolledListbox::insert } \ {-cmd "xview" -passthrough .lb } \ {-default 1 -passthrough .lb } wattr subclass $w -cmdlist ScrolledListbox a possible variation would be wattr subclass $w -cmdlist ScrolledListbox {\ {-cmd "delete" -minargs 1 -maxargs 2 -help " ?endindex?" \ -proc ::ScrolledListbox::delete } \ {-cmd "insert" -minargs 1 -help " arg ?arg?" \ -proc ::ScrolledListbox::insert } \ {-cmd "xview" -passthrough .lb } \ {-default 1 -passthrough .lb } \ } to prevent the need for having a name for the command list (this would, however, increase the complexity of implementing it in an efficient way) 4. All wattr subcommands ------------------------------------------------------------------------------- already known: "alias" maps attributes to variables "arraymap" maps all attributes of a widget to an array variable "cget" retrieves the attribute value "configure" ?attribute value? ... sets and retrieves values "cinfo" prints meta information about the attribute "description" class ?args? manages descriptions "subclass" args builds megawidgets "varname" returns the name of the variable which is linked to the attribute "exist" ?attribute? If the attributename is omitted, wattr reports with "1" if it has an internal attribute list linked to the given widget. If the attribute argument is given, it checks if this argument is inside the attribute list. other commands -------------- "createobject" ?class? used in conjunction with the "oattr" command to create an internal identifier which is used instead of a widget path "changed" used to test if one of the elements in testlist was changed as a result of a "wattr configure" call Sample: % set chlist [wattr configure .foo -bar 1 -spong 2 -width 5] -bar -spong -width % wattr changed { -width -height } $chlist 1 "info" ?globpattern? prints out either all DescriptionNames or the names of all widgets which have attribute information. If a globpattern is given, the result list will be restricted to all names matching this pattern. "parseclassname" Tries to locate a "-class " in a configure style list and returns if found, otherwise returns . This is typically used for subclassing. Sample: % wattr parseclassname [list -abc 1 -def 2] DefClass DefClass % wattr parseclassname [list -abc 1 -def 2 -class Abc] DefClass Abc "propagate" "all" forces an internal "configure" call to all propagated attributes of the megawidget (if a -propagate option was set in the description). "off" turns off propagating. "on" switches propagation on. "destroy" Removes all wattr structures for this widget. Never call this directly for a Tk widget. Normally a "wattr'ized" widget gets a bindtag, which does this by default. This subcommand only makes sense if "oattr" objects are used instead of widgets. 5. "oattr", using "wattr" without widgets ------------------------------------------------------------------------------- Because we needed to store attributed objects in our application (objects of an XML tree), it appeared useful to have the functionality of "wattr" without the need of creating a widget. Hence I created "oattr", which is a poor man's itcl. A short sample will demonstrate the usage: % oattr create mycmd mycmd % mycmd description create AbcClass [ list -name "att1" -default "bar" ] {-name att1 .....} % mycmd createobject abc AbcClass abc % mycmd cget abc att1 bar % mycmd configure abc -foo goo -foo % mycmd configure 111 -bar 2 "111" not found % mycmd destroy abc % oattr objects mycmd % oattr destroy mycmd % oattr objects % "oattr" creates object commands. This object command can create internal objects via "createobject" , which may be attributed in the same way as a widget with "wattr". It is possible to define descriptions in the same way as for "wattr". It is also possible to define changeprocs (with one parameter more, the name of the objectcommand , "mycmd" in the sample). Only propagation is not supported (because there are no subwidgets). It will be also possible to use "subclass" to allow the access to the object via a tcl-command, which mimics a bit the itcl way. However, it isn't implemented at the moment (and works only together with Tk, which is also a drawback).