关于
Button
最诡异的事情大概就是与变量作用域相关的命令了。
Button
事件是作用域全局域下而非任何过程函数中。如果
Button
是在一个过程函数中创建的,那么该
Button
的命令之后将在不同的作用域中执行。即使是使用
binding
的事件处理,也将在全局域中执行。
我认为这是一个关于定义与执行的时间问题。举例来说,当定义一个
Button
时可以使用到一组变量,但在使用该
Button
的时候却用的是另一组变量。当遇到混合上下文环境的情况,这就变得很混乱了。以下例子中的
Button
命令使用到了两个变量:
x
和
val
。其中
x
是在执行中需要使用的全局变量,,本地变量
val
在定义
Button
时使用。
proc Trouble
{args} {
set b 0
# Display the value of x, a global variable
label .label -textvariable x
set f [frame .buttons -borderwidth 10]
# Create buttons that multiply x by their
value
foreach val $args {
button $f.$b -text $val \
-command "set x \[expr \$x *
$val\]"
pack $f.$b -side left
incr b
}
pack .label $f
}
set x 1
Trouble -1 4
7 36
这个例子用了一个
label
来设置
textvariable
属性来显示
x
的当前值,该
x
总是一个全局变量。在这里,因为
x
不在
Trouble
中使用(只是被定义),所以不用使用
global
来说明
x
是全局变量(当然,用了也没关系)。
Button
命令之后则将在全局范围被使用。
但是这个
Button
命令的定义非常丑陋,在
foreach
中的定义的
Button
使用了本地的变量
val
,而其他变量的实值替换将发生在之后的全局范围内。因此需要前缀反斜杠使
$x
和
expr
不在双引号被转义。
set x \[expr
\$x * $val\]
我们举个反例来说,以下的这里例子中给
x
在定义过程中被直接赋值了一个常量,因而无法达到上面例子中的目的,显然是不正确的。
button $f.$b
-text $val -command "set x [expr $x * $val]"
另外一个不正确的做法是对整个命令使用花括号(就是
“”
)。这么做则是过犹不及了,所有的变量都将在全局范围内执行时被实值替换,这个时候
tcl
解析器可能发生提示发生错误,说找不到某些变量。