Tcl/Tk Cookbook - Basics of Tk


Step 3: Display attribute - value pairs

Script

Append the following lines to appl1.tcl [ For clarity and good programming practice, place any global declarations at the top of the body the script (just below the line #!/usr/bin/wish) and in procedures immediately after the declaration of the procedure. Any initialisation should also be placed before the value is set or rest from within the script. ]


global aList vList

set aList {}
set vList {}
set maxl 0

set b [.rc.b config]

foreach e $b {
	lappend aList [lindex $e 0]
	lappend vList [lindex $e 4]
	set a [lindex $e 0]
	if { [string length $a] > $maxl } {
		set maxl [string length $a]
		}
	}

The first line sets two global variables aList and vList and the next two lines initialise these two variables to null list. the last line sets a variable maxl to zero.

The command set b [.rc.b config] invokes the widget command .rc.b to get its list current configuration options and assigns it to the variable b. Note that b is a list of lists. Each nested list contains the configuration option such as -background followed by information regarding that option, the fifth of which is the value.

The first of the foreach loop access nested list "e" of the list "b"

  1. gets the option (at the 0th index of list e) , appends it to "aList"
  2. gets the current value of the option (at the 5th index of list e),
  3. computes the maximum length of the option string and assigns it to maxl. This is used subsequently to position the label strings right justified and have neat looking form type interace

Now you need to create an interface to display these pairs of values. The script below achieves this:


set i 0

frame .rc.fff -height 40 

pack .rc.fff
foreach a $aList {
	set ff [frame .rc.fff.sub$i]
	pack $ff
	label $ff.lab -text $a -width $maxl -anchor e
	entry $ff.ent
	bind $ff.ent  [list reJig .rc.b $a]
	$ff.ent insert 0 [lindex $vList $i]
	pack $ff.lab $ff.ent -side left -in $ff
	incr i
	}

Set a counter "i", initialising it to zero. frame .rc.fff -height 40 creates a frame .rc.fff, of height 40 pixels as a child of .rc and pack .rc.fff packs it below the button .rc.b by default.

The foreach element "a" of the list "aList"

  1. a frame whose name is made up with counter "i" (e.g., .rc.fff.sub0) is created as a child of .rc.fff and assigned to the variable "ff" {Note that this is a short-cut to giving long widget names}. The child frame is packed.
  2. within the frame given by "ff" a label widget whose text is the configuration option is created. The width of the label is set to the value of "maxl" to create uniform label sizes. The label is anchored to the east of the frame to ensure appearance.
  3. an entry widget whose name is made up by appending .ent to the value of "ff" is created. Entry widgets are used to display editable one-line text strings.
  4. a binding to the event (user types in a string and hits the Return key) in the entry widget is created. [list reJig .rc.b $a] substitutes the value of "a" and creates the script {a command to invoke the procedure reJiG with the parameters ".rc.b" and "a "} to be invoked.
  5. the current value, if any, of the attribute is inserted in the entry widget
  6. the label and the entry widget are packed inside their parent, given by "ff", from left to right.
  7. increment the counter

Note: As in any shell programming language, in Tcl/Tk too there are more than one way of achieving certain results. For instance the script for the binding could have been specified as "reJig .rc.b $a". Using [list * * ] ensures proper variable substitutions are carried out and a proper list structure whose elements together form a single command is generated.

If you try {reJig .rc.b $a}, you will find that "a" is not replaced by its value because it is within the curly braces. As a result the procedure reJig will receive the string $a rather than the value of a.

Note also that since the widget hierarchy name uniquely identifies a widget .rc.fff.sub0.ent is different from .rc.fff.sub1.ent.

Appending these lines of script in appl1.tcl and executing should produce: