Reputation: 1122
I can't bind
the Escape
and Return
keys in my Tcl/Tk code. The following code reproduces the bug. When I hit Esc
or Enter
key I get the following error message:
Error: can't read "cmd": no such variable
proc OkCancel { cmd } {
button .${cmd}.ok -text "OK" -command [list myOk $cmd ]
button .${cmd}.cancel -text "Cancel" -command [list myCancel .$cmd]
grid .${cmd}.ok .${cmd}.cancel -sticky e
bind .$cmd <Return> { myOk $cmd ; break }
bind .$cmd <Escape> { myCancel .${cmd} ; break }
}
proc myOk { cmd } {
puts "The command name is = $cmd"
}
proc myCancel { arg } {
destroy $arg
}
proc test { } {
set cmd "hello"
toplevel .$cmd
OkCancel $cmd
}
test
Upvotes: 1
Views: 2514
Reputation: 55573
That's because when an event fires, the script bound to it gets eval
uated at the global level (as per the bind
manual). That is, in case of your <Return>
binding, the script myOk $cmd ; break
will be executed, literally. Hence, if there exists no variable named "cmd" in the global namespace at the time your script runs, the error you have shown will be triggered.
To fix the problem, there are several ways:
$cmd
substitution be evaluated at the time the script is created and bound. To do this, just replace {} with "" to allow variable substitution, that is, if you'd write bind .$cmd <Return> " myOk $cmd ; break "
the bound script would be myOK hello ; break
bind .$cmd <Return> [list mycallback $cmd]
and then make sure you have defined mycallback
procedure accepting one parameter. This way you can write generic event handlers which are parameterized by whatever parameters you need at the time of the binding.namespace code
or a similar tool to make your script executed in a specified namespace which has the specified variable defined.In all cases beware that since your $cmd may in certain cases expand to something odd, it's a good idea to protect the whole script from such a situation--that's what [list ...]
does in the second example (see this for more info).
Upvotes: 5