I'm trying to construct a (Tcl/)Tk command (to be associated with a widget's -command
), that contains a variable that must be expanded at runtime.
In the original code this variable had a fixed name (so everything was simple and we used {...}
):
Something like this:
proc addaction {widgid} {
$widgid add command -label "Action" -command {::actioncmd $::targetid}
}
addaction .pop1 # dynamic target is read from $::targetid
set ::targetid .foo ## now the action for the .pop1 widget targets .foo
set ::targetid .bar ## now the action for the .pop1 widget targets .bar
But now I would like to change this so we can replace the to-be-expanded variable with a fixed value in the "constructor". The constraints are:
- to keep the signature of
addaction
(thereforeid
must be optional) - not to touch
::actioncmd
at all.
So I came up with something like this:
proc addaction {widgid {id $::targetid}} {
$widgid add command -label "Action" -command [list ::actioncmd $id]
}
addaction .pop1 # (as before)
addaction .pop2 .foo # static target for .pop2 is *always* .foo
Unfortunately my replacement code, doesn't work as the the $::targetid
variable is no longer expanded. That is, if I trigger the widget's command I get:
$::targetid: no such object
Obviously the problem is with dynamically constructing a list that contains $args. Or more likely: the subtle differences between lists and strings.
At least here's my test that shows that I cannot mimick {...}
with [list ...]
:
set a bar
set x {foo bar}
set y [list foo $a]
if { $x eq $y } {puts hooray} else {puts ouch}
# hooray, the two are equivalent, and both are 'foo bar'
set b {$bar}
set x {foo $bar}
set y [list foo $b]
if { $x eq $y } {puts hooray} else {puts ouch}
# ouch, the two are different, x is 'foo $bar' whereas y is 'foo {$bar}'
So: how can I construct a command foo $bar
(with an expandable $bar
) where $bar
is expanded from a variable?
A naive solution could be:
proc addaction {widgid {id {}}} {
if { $id ne {} } {
set command [list ::actioncmd $id]
} else {
set command {::actioncmd $::targetid}
}
$widgid add command -label "Action" -command $command
}
But of course, in reality the addaction
proc adds more actions than just a single one, and the code quickly becomes less readable (imo).