复杂Tcl/Tk应用程序中的全局变量?设计模式、惯例、风格?

复杂Tcl/Tk应用程序中的全局变量?设计模式、惯例、风格?,tcl,tk,Tcl,Tk,每当我编写一个Tcl/Tk应用程序时,我都会被使用全局变量的必要性所困扰,因为回调脚本是在顶级范围内进行计算的,我总是希望对回调使用proc来隐藏复杂性。但我讨厌在我所有的程序中都有全局变量 我的解决方法是使用一个参数作为全局变量的名称,并使用upvar引用它,这样至少我可以看到哪个全局变量正在作为proc调用的一部分使用(和修改)。通常这是一个单一的状态数组 我的应用程序似乎总是以主窗口中的按钮列表的形式出现,这些按钮触发执行实际工作、查询数据库、存储和修改结果等的顶层 我很想为每个顶级使用不

每当我编写一个Tcl/Tk应用程序时,我都会被使用全局变量的必要性所困扰,因为回调脚本是在顶级范围内进行计算的,我总是希望对回调使用proc来隐藏复杂性。但我讨厌在我所有的程序中都有全局变量

我的解决方法是使用一个参数作为全局变量的名称,并使用upvar引用它,这样至少我可以看到哪个全局变量正在作为proc调用的一部分使用(和修改)。通常这是一个单一的状态数组

我的应用程序似乎总是以主窗口中的按钮列表的形式出现,这些按钮触发执行实际工作、查询数据库、存储和修改结果等的顶层

我很想为每个顶级使用不同的名称空间,这样子窗口小部件就可以引用这个名称空间中的变量,而不会破坏真正的全局变量,但我不确定这是否是一个好主意


其他Tcl/Tk程序员做什么?

正如您所建议的,您可以使用名称空间来隔离应用程序不同部分的过程和变量。您感兴趣的命令是
名称空间代码
namespace-code
命令“捕获当前名称空间上下文”,并使名称空间对于包含回调非常有用。对于中小型应用程序,名称空间技术对我来说相当有效。

许多应用程序都非常简单,只需使用全局变量就可以了

但是,如果您需要更复杂的东西,那么首先要尝试的可能是将全局变量设置为数组,这些数组通过对话框的顶级小部件的名称进行索引。获得顶级的身份通常是相当容易的;您可以将其存储在绑定/回调中(使用
list
命令可以正确引用),也可以在绑定中使用
[winfo topflevel%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
}
proc makeDialog{w}{
全局对话状态
顶级$w
按钮$w.btn-文本“Foo Bar!”-命令[列表对话框回调$w]
绑定$w{cancelDialog%w}
设置对话框状态($w)123
#等等,让对话变得漂亮。。。
}
proc dialogCallback{w}{
全局对话状态
增量对话框状态($w)
}
过程取消对话框{somewidgetwithfocus}{
全局对话状态
设置w[winfo顶级$SomeWidgetWithFocus]
放置“状态=$dialogState($w)”
销毁$w
}
(我将
winfotopflevel
放在回调中,因为让绑定脚本本身尽可能简单是个好主意。)

您也可以轻松地为此使用命名空间变量。全局命名空间并不特别,但是优秀的TCL程序员通常认为它是TCL本身和应用程序的属性;鼓励库包使用其他名称空间。(可以使用数组的变体,例如8.5以后的字典。)


也可以使用对象系统(现在通常推荐的是TclOO、incrtcl、XOTcl和Snit)。如果你想让建议集中在其中一个问题上,请问另一个问题。

谢谢Donal,你一如既往地很有帮助——用顶级索引是一个好主意,可能会满足我的所有需要。“名称空间代码”方法看起来也很有趣,尽管有点模糊。关于面向对象的方法,有针对这种用例的教程吗?