我正在尝试使用wget.exe
从本地网站获取一些文本。我使用 TCL 代码(如下所示(来启动wget.exe
。当TCL等待wget.exe
的响应和结果时,鼠标没有响应。甚至没有到窗口右上角的小x来关闭程序。
我在互联网上搜索了一些答案,只找到指向绑定的结果。
while {[catch {set line1 [exec wget.exe
--no-check-certificate
-q
-O -
-T $tout
-t 1
$serverip$url]}]} {
# ACCESS HAS FAILED AND TEST HOW MANY TIMES?
Some more code here
}
在等待wget.exe
输出时,我希望能够在超时之前通过鼠标单击中止和关闭程序wget.exe
。
假设您在 Tk GUI 的上下文中执行此操作...
您需要做的是异步运行子进程,以便在子进程运行时继续为 GUI 事件循环提供服务。如果我们使用 Tcl 8.6(或更高版本(,这在您的情况下要容易得多,因为我们可以使用协程来简化所有事情。
# A global variable that you can hook into the GUI to get a crash stop
set StopRightNow 0
coroutine doWget apply {{} {
global tout serverip url StopRightNow
while true {
set subprocess [open |[list wget.exe
--no-check-certificate
-q
-O -
-T $tout
-t 1
$serverip$url]]
fconfigure $subprocess -blocking 0
# Arrange for the coroutine to resume whenever there's something to do
fileevent $subprocess readable [info coroutine]
set lines {}
while {![eof $subprocess]} {
yield
# Check for override!
if {$StopRightNow} return
if {[gets $subprocess line] >= 0} {
lappend lines $line
}
}
fconfigure $subprocess -blocking 1
if {![catch {close $subprocess} errors]} {
break
}
# Do something to handle the errors here...
puts "Problem when reading; will retryn$errors"
}
# At this point, $lines has the list of lines read from the wget subprocess. For example:
puts "Read the output..."
foreach line $lines {
puts "[incr lineNumber]: $line"
}
}}
好吧,这有点大。让我们将其核心分解为一个过程。
proc asyncRunSubprocess args {
global StopRightNow
set subprocess [open |$args]
fconfigure $subprocess -blocking 0
# Arrange for the coroutine to resume whenever there's something to do
fileevent $subprocess readable [info coroutine]
# Accumulate the subprocess's stdout
set lines {}
while {![eof $subprocess]} {
yield
if {$StopRightNow} {
return {{} -1 interrupted {}}
}
if {[gets $subprocess line] >= 0} {
lappend lines $line
}
}
# Close down the subprocess; we've got an EOF
fconfigure $subprocess -blocking 1
set code [catch {close $subprocess} errors opts]
return [list $lines $code $errors $opts]
}
然后我们可以像这样制作外部协程:
coroutine doWget apply {{} {
global tout serverip url
while true {
set results [asyncRunSubprocess
wget.exe --no-check-certificate -q -O - -T $tout -t 1 $serverip$url]
lassign $results lines code errors
if {$code < 0} return elseif {$code == 0} break
# Do something to handle the errors here...
puts "Problem when reading; will retryn$errors"
}
# At this point, $lines has the list of lines read from the wget subprocess. For example:
puts "Read the output..."
foreach line $lines {
puts "[incr lineNumber]: $line"
}
}}
请注意,Tcl的协程(与许多其他语言不同(可以非常愉快地在它们调用的过程中挂起。