Version 6 of WhoAmI? -Letting proceedurally added widgets know their names

Updated 2005-09-01 12:25:51

WJG (1st September 2005) There's probably something described in the small print of the Tcl man pages that will do something similar but... If I add new functionality to an app I like to pack buttons 'n' stuff on the fly in which case there is no guarentee as to what a widget name might be. Widget bindings allow us to know which item was clicked although the button -command switch has no such choice. To cross this gap we have to work with references. Because the 'bind all' take presidence over the individual button command we can use a binding to set a global variable which subsequent commands can access.

The following code example allows us to create buttons and then allows the button command to make adjustments to itself.

 #----------------------------------------------------------------
 # whoami.tcl
 #----------------------------------------------------------------
 #
 # Making a button aware of just who it is.
 # This can be useful if wigets are built proceedurally and pathnames
 # are not defined explicitly.
 #
 #----------------------------------------------------------------

 # set global array for where the last 2 B1 events occured
 array set ::widget {
   active ""
   last ""
 }

 bind all <Button-1> {
  set ::widget(last) $::widget(active)
  set ::widget(active) %W
 }

 #----------------------------------------------------------------
 proc whoami {} {
  if {[$::widget(active) cget -text] == "Clickme!"} {
    $::widget(active) config -text "Clicked!"
    } else {
    $::widget(active) config -text "Clickme!"
    }
  puts "I am \"[winfo name ${::widget(active)}]\" and I live in \"[winfo parent ${::widget(active)}]\"."
 }

 #----------------------------------------------------------------

 console show 
 expr srand(1)
 set base .t2 
 toplevel $base

 button .b1 -text Clickme! -command {
   whoami
   # use randomly created path names
   set i [string trimleft [expr rand()] 0.]
   pack [button $base.b$i -text "Button $i" -command whoami]
 }
 pack .b1

 bind .b1 <Button-1> {puts "I am %W -hello from my unique <B1> binding."}

Brian Theado - The value passed to -command isn't limited to being just a command name--arguments can be passed as well (see example on button page). It should work to add an argument to your button procedure:

 proc whoami button {...}

and the pass the window name when -command is configured:

 pack [button $base.b$i -text "Button $i" -command [list whoami $i]]

WJG Is not a matter of passing arguments -this I'm fully aware of. In the example that you give only the value of i is passed. My intention is to pass the whole widget path. The problem I've set myelf is to be able to copy and paste (using a private buffer) embedded windows between text widgets. As the embedded windows have additional associated tags, I need as nuch as possible enable button command invoked procs to know where they were called from. Later I plan to add some sort of file save and loading of embedded windows.

Brian Theado - My mistake. I meant to pass the full widget path -- [list whoami $base.b$i], not just $i. Doing that, you would be able to replace ::widget(active) with the input argument "button" in "whoami". Maybe that still isn't what you are after.