为了证明我的问题,我编写了一个示例代码,如下所示
button .a -text check -command abc
pack .a
set a 0
proc abc {} {
pqr
}
proc pqr {} {
global a
puts "in pqr proc"
# Want to break initial vwait
set a 1
# Want to start a new vwait
vwait a
puts "vwait in pqr break"
}
vwait a
puts "Initial vwait break"
通过这种方式,我的初始视频似乎永远不会破坏。
任何想法如何实现这一目标。 我想破坏初始vwait并在同一个proc中启动一个新的vwait。
答案 0 :(得分:0)
代码有效,但并不像你期望的那样。特别是,顶级vwait a
不会继续,直到按下按钮的事件处理结束,这在内部vwait a
终止后发生。 (但外部vwait
被标记为终止;它只是想首先清除它的内部调用堆栈。)这既简单又难以解决,它也是适用于update
命令。 {T}社区中update
有时被称为Considered Harmful并且没有任何意义(是的,这也适用于vwait
)。
您真正想要做的是构建代码,以便它使用回调,并且最多只能使用一个vwait
。
proc oneShotTrace {varname callbackScript} {
upvar \#0 $varname v
trace add variable v write [list oneShotTraceCallback $varname $callbackScript]
}
proc oneShotTraceCallback {varname callbackScript} {
upvar \#0 $varname v
trace remove variable v write [list oneShotTraceCallback $varname $callbackScript]
uplevel \#0 $callbackScript
}
button .a -text check -command abc
pack .a
set a 0
proc abc {} {
pqr
}
proc pqr {} {
global a
puts "in pqr proc"
# Want to break initial vwait
set a 1
oneShotTrace a {
puts "vwait in pqr break"
}
}
oneShotTrace a {
puts "Initial vwait break"
}
vwait forever
这是对代码的重大重新排列。使用Tcl 8.6的协程可以使事情变得更加混乱。
proc oneShotTrace {varname callbackScript} {
upvar \#0 $varname v
trace add variable v write [list oneShotTraceCallback $varname $callbackScript]
}
proc oneShotTraceCallback {varname callbackScript} {
upvar \#0 $varname v
trace remove variable v write [list oneShotTraceCallback $varname $callbackScript]
uplevel \#0 $callbackScript
}
button .a -text check -command abc
pack .a
set a 0
proc abc {} {
coroutine c[incr ::co_count] pqr
}
proc pqr {} {
global a
puts "in pqr proc"
# Want to break initial vwait
set a 1
oneShotTrace a [info coroutine]
yield
puts "vwait in pqr break"
}
oneShotTrace a {
puts "Initial vwait break"
}
vwait forever
嗯,这似乎仍然令人困惑。它在实际代码中不那么糟糕,其中保留协程的复杂性不仅仅是通过诸如本地堆栈框架中的变量易于使用以及易于理解的流程这样的小问题来证明。 (另外,您可以在协程内部调用的过程中隐藏yield
...)