每当我编写Tcl / Tk应用程序时,我都会被使用全局变量的必要性所困扰,因为回调脚本是在顶级范围内进行评估的,而我总是希望使用proc来进行回调来隐藏复杂性。但我讨厌在我的所有程序中使用全局变量......
我的方法是使用一个参数作为全局变量的名称,并使用upvar来引用它,所以至少我可以看到哪个全局变量正被使用(和修改)作为proc调用的一部分。通常这是一个单独的STATE数组。
似乎我的应用程序始终采用主窗口中的按钮列表的样式,这些按钮会触发执行实际工作,查询数据库,存储和修改结果等的按钮。
我很想为每个顶层使用不同的命名空间,以便子窗口小部件可以引用此命名空间中的变量而不会破坏真正的全局变量,但我不确定这是不是一个好主意。
其他Tcl / Tk程序员做了什么?
答案 0 :(得分:2)
许多应用程序都很简单,只需使用全局变量即可。
但是,在需要更复杂的东西的地方,首先要尝试的是使全局变量成为由对话框的顶层窗口小部件名称索引的数组。获得顶层的标识通常很容易;您可以将其存储在绑定/回调中(list
命令对于正确引用很有用),或者您可以在绑定中使用[winfo toplevel %W]
。
proc makeDialog {w} {
global dialogState
toplevel $w
button $w.btn -text "Foo Bar!" -command [list dialogCallback $w]
bind $w <Escape> {cancelDialog %W}
set dialogState($w) 123
# Etc with making the dialog pretty...
}
proc dialogCallback {w} {
global dialogState
incr dialogState($w)
}
proc cancelDialog {someWidgetWithTheFocus} {
global dialogState
set w [winfo toplevel $someWidgetWithTheFocus]
puts "state = $dialogState($w)"
destroy $w
}
(我把winfo toplevel
放在回调中,因为保持绑定脚本本身尽可能简单是一个好主意。)
您也可以轻松使用命名空间变量。全局命名空间不是 特殊,但优秀的Tcl程序员通常认为它是Tcl本身和应用程序的属性;鼓励库包使用其他命名空间。 (可以使用数组的变体,例如从8.5开始的字典。)
也可以使用对象系统(目前通常推荐的是TclOO,incr Tcl,XOTcl和Snit)。如果您希望将建议集中在其中一个上,请提出另一个问题。
答案 1 :(得分:1)
正如您所建议的那样,您可以使用命名空间来隔离应用程序不同部分的过程和变量。您感兴趣的命令是namespace code
。 namespace code
命令“捕获当前的命名空间上下文”,并使命名空间对包含回调很有用。对于中小型应用程序,命名空间技术对我来说效果相当不错。