【问题标题】:how do I update a variable via a tk window by name如何通过名称通过 tk 窗口更新变量
【发布时间】:2014-08-19 00:10:47
【问题描述】:

考虑以下情况:

namespace eval ::mydialog {}

proc ::mydialog::show {w varName args} { 
   upvar 1 $varName theVar
   # now I can access theVar

   # (1)

   # code defining/creating my window
   # here some widgets for user interaction are created, 
   #   some of which will call ::mydialog::_someCallback

   wm protocol $w  WM_DELETE_WINDOW [list ::mydialog::close $w]
}

proc ::mydialog::_someCallback {}  {
   # how do I access theVar here?

   # (2)
}

proc ::mydialog::close { w } {
   # here some changes are supposed to be written back into varName in the calling scope,
   #    how do I do that?!

   # (3)

   destroy $w
}

我试图弄清楚如何 (a) 从调用范围获取一个变量 (b) 在所有三个 proc 中都可用,以及 (c) 将任何更改写回所述变量。

(a) 我通常会使用 'upvar 1 $varName theVar' 来解决 (b) 我通常会使用命名空间变量来解决 (c) 只要我们只有一个 proc 会与 (a) 一起自动发生,因为我们将处理该变量的本地别名

问题在于 upvar 仅在 (1) 中有效(至少按预期)。 我可以在 (1) 中使用 upvar 并将其保存/复制到命名空间变量中,这将解决 (a) 和 (b),但不能解决 (c)。

如果有人能在这里指出正确的方向,我将不胜感激。

另外,由于我对 Tcl/Tk 比较陌生,我的概念可能并不理想,也欢迎提出更好的设计建议。

【问题讨论】:

  • 我不完全确定您要做什么,但是您可以使用theVar 调用proc 并在proc 末尾使用return 来检索theVar 有或没有变化。也许您可以在此处和此处(例如在调用不同的 proc 之前和之后)放置一些可重复的小 sn-p 您想要获得的内容,并说出您期望得到的内容。
  • @Jerry 将 VAr 作为参数传递并使用 return 将其返回将适用于“正常”过程。但不是介于两者之间的 tk 对话框/窗口。问题是 ::mydialog::show 与应该设置新值的回调函数(例如,对于按钮单击)没有直接的“连接”/关系。正如 Hoodiecrow 指出的那样,可以使用全局命名空间作为参考点将它们联系在一起。我不确定我是否喜欢这样(从设计的角度来看),但我没有看到其他方式。

标签: namespaces tcl tk upvar


【解决方案1】:

我建议你使用一个命名空间变量来保存变量的名称,upvar 使用全局范围。

namespace eval ::mydialog {
    variable varName
}

proc ::mydialog::show {w _varName args} { 
    variable varName $_varName
    upvar #0 $varName theVar

}

proc ::mydialog::_someCallback {}  {
    variable varName
    upvar #0 $varName theVar
    puts $theVar
}

proc ::mydialog::close { w } {
    variable varName
    upvar #0 $varName theVar
    set theVar newval
}

set globalvar oldval
# => oldval
::mydialog::show {} globalvar
::mydialog::_someCallback
# => oldval
::mydialog::close {}
# => newval
puts $globalvar
# => newval

请注意语法高亮失败:#0 $varName theVar 并不是真正的注释。

这也适用于命名空间变量:如果您在 ::foobar 命名空间中有一个名为 nsvar 的变量,您可以像这样使用它:

set ::foobar::nsvar oldval
::mydialog::show {} ::foobar::nsvar
::mydialog::_someCallback
::mydialog::close {}
puts $::foobar::nsvar

具有相同的效果。

但是,您不能以这种方式使用某些过程的局部变量。

使这变得非常简单的一种方法是使用 Snit 小部件而不是 Tcl 过程的集合。

文档:namespaceprocputssetupvarvariable

Snit 文档:man pagefaq(faq 也是一种介绍)

​​>

【讨论】:

  • 我认为您的最后一点(但是,您不能以这种方式使用某些过程的局部变量。)是我偶然发现的。如果我理解正确,我必须使用完全限定的 varNames,否则将它们全部填充到全局命名空间中:-(在我看来这不是很好的风格。我尝试使用具有相对级别的 upvar,由于“回调”而无法正常工作tk 实践的魔法”(显然 tk 回调始终是第 2 级,并且与它们定义的范围无关;事后看来确实有道理)
  • @Peter:你应该在这里使用命名空间变量。在这种情况下,您可以通过分别注册命名空间和变量名并使用namespace upvar 而不是常规的upvar 来减少调用的痛苦。否则,是的,就是这样。不过,这不是错误,而是小部件系统工作方式的结果。不过,请参阅我添加的关于 Snit 的评论。
猜你喜欢
  • 2021-08-03
  • 1970-01-01
  • 2013-03-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-04-26
  • 2022-08-17
  • 1970-01-01
相关资源
最近更新 更多