|
Description:
Tk utility - change the mouse pointer to a watch cursor, execute a script, then restore the original cursor. Works properly even if the script raises an error, [break]s, [return]s, or any other exceptional return code.
Source: Text Source
proc withBusyCursor {body} {
global errorInfo errorCode
set busy {}
set list {.}
while {$list != ""} {
set next {}
foreach w $list {
catch {set cursor [$w cget -cursor]}
if {[winfo toplevel $w] == $w || $cursor != ""} {
lappend busy $w $cursor
set cursor {}
}
set next [concat $next [winfo children $w]]
}
set list $next
}
foreach {w _} $busy {
catch {$w configure -cursor watch}
}
update idletasks
set rc [catch {uplevel 1 $body} result]
set ei $errorInfo
set ec $errorCode
foreach {w cursor} $busy {
catch {$w configure -cursor $cursor}
}
return -code $rc -errorinfo $ei -errorcode $ec $result
}
The license for this recipe is available here.
Discussion:
Got a section of code in a GUI that takes a few seconds to execute?
Wrap it in a call to [withBusyCursor] to give the user feedback.
Known problems: Only tested on Unix; it doesn't seem to always work
on Windows. I'm not sure if it should use [update] or [update idletasks].
Notes: Unlike the BLT [busy] command, this doesn't block user input.
In practice this doesn't seem to be a problem -- when the cursor changes,
users tend to stop clicking until it changes back.
The code also illustrates a useful idiom for breadth-first traversal,
the correct way to pass exceptional return conditions up the call stack,
and one of Tcl's neatest features -- the ability to define new control structures.
|