我有一个内置在Tcl / Tk中的GUI,它有一个按钮可以打开一个目录。 目录可能非常大,所以我不想在等待时锁定GUI。
为了实现这一点,我使用open命令管道和vwait,但是当tar运行时,GUI仍然没有响应。这是我的代码:
set ::compress_result 0
set pipe [open "|$tar_executable -cf $folder_to_tar.tar $folder_to_tar" r+]
fileevent $pipe readable "set ::compress_result [gets $pipe line]"
vwait ::compress_result
set return_value $::compress_result
unset ::compress_result
close $pipe
为什么这仍会阻止Tcl事件循环并锁定GUI?
答案 0 :(得分:2)
你遇到的关键问题是这一行:
fileevent $pipe readable "set ::compress_result [gets $pipe line]"
此从管道中立即读取行,因为[gets …]
位于双引号字符串中。改为:
fileevent $pipe readable {set ::compress_result [gets $pipe line]}
使事情有效,因为它推迟了管道的读数,直到管道变得可读。但是,要做到这一点,它依赖于全局的pipe
变量。实际上这样做更好:
fileevent $pipe readable [list apply {pipe {
global compress_result
set compress_result [gets $pipe line]
}} $pipe]
调试非常难看和笨拙,所以我们实际使用帮助程序:
proc pipedone {pipe} {
global compress_result
set compress_result [gets $pipe line]
}
fileevent $pipe readable [list pipedone $pipe]
这里使用list
确实“将此引用为可运行的脚本以供日后使用”,以处理变量中可能出现的任何意外诡计。它知道如何正确引用事物,所以你不必这样做。
在Tcl 8.6中,你最好使用协程。
coroutine piperead apply {{tar folder} {
# Open the pipe
set pipe [open |[list $tar -cf $folder.tar $folder] "r"]
# Wait until readable
fileevent $pipe readable [info coroutine]
yield
# Read and close
set return_result [gets $pipe line]
close $pipe
return $return_result
}} $tar_executable $folder_to_tar
答案 1 :(得分:0)
添加
fconfigure $pipe -blocking false
打开后,管道会有所帮助。