如何响应鼠标单击



我正在尝试使用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的协程(与许多其他语言不同(可以非常愉快地在它们调用的过程中挂起。

最新更新