James Bonfield proposed a C code patch in Nov. 2000 that would "fix" Tk's use of the native Windows open file dialog. According to Tktoolkit bug 611615 [1] the patch has been applied to Tk 8.5a0. See also bugs 220057 and 219985.
But for those of us stuck with Tcl/Tk 8.4 for a while, Bob Techentin wrote a procedure to drain the event queue on demand, inspired by Donal Fellows' suggestion to drain events to a label widget. This procedure searches children of "." for a simple label widget, then calls grab and update to syphon off any extra mouse clicks.
#-----------------------------------------------------------------
#
# drainEventQueue
#
# This code uses [grab] to direct all events to an
# inoccuous widget (a label), drains the event
# queue by calling [update], then releases the grab.
# The draining widget must be mapped, so we search
# [winfo children .].
#
#-----------------------------------------------------------------
proc drainEventQueue {} {
# Search for a mapped Label widget in children of "."
set wlist [winfo children .]
while { [llength $wlist] > 0 } {
set w [lindex $wlist 0]
set wlist [lrange $wlist 1 end]
# If we've got a mapped Label Widget, drain the queue
if { [winfo ismapped $w] } {
if { [winfo class $w] eq "Label" } {
grab $w
update
grab release $w
return
}
# Not a label, but ismapped, so add chldren to search
set wlist [concat $wlist [winfo children $w]]
}
}
# if we fall through, then there wan't a suitable widget.
# Tough luck.
}Call it like this set filename [tk_getOpenFile]
# Evade Windows double-click bug
if { $::tcl_platform(platform) eq "windows" } {
drainEventQueue
}Mick O'Donnell presented a workaround in December 2001 which renames and wraps tk_getOpenFile/tk_getSaveFile with procs that create a temporary toplevel and use grab and update to drain extra events from the queue.
## PATCH to AVOID THE tk_getOpenFile double-click problem # Fix suggested by Bob Sheskey ([email protected]) 1997 # Packaged into a code patch by Mick O'Donnell ([email protected]) 2001 # global tcl_platform if { $tcl_platform(platform) == "windows"} { # Don't move the original procs twice if { [info commands orig_tk_getOpenFile] == {}} { # Rename the procs elsewhere rename tk_getOpenFile orig_tk_getOpenFile rename tk_getSaveFile orig_tk_getSaveFile } # Provide a new definitions proc tk_getOpenFile {args} { if [winfo exists .temp787] {destroy .temp787} wm withdraw [toplevel .temp787] grab .temp787 set file [eval [concat orig_tk_getOpenFile $args]] update destroy .temp787 return $file } proc tk_getSaveFile {args} { if [winfo exists .temp787] {destroy .temp787} wm withdraw [toplevel .temp787] grab .temp787 set file [eval [concat orig_tk_getSaveFile $args]] update destroy .temp787 return $file } }
Donald Arseneau presented a pure-Tcl workaround in February 2003 which revectors widget bindings for a fraction of a second after an expose event. I (RWT) couldn't get this to work on Windows XP. I suspect that the trailing <Key-up> event is in the queue before the <Expose> event fires.
# Disable key and button events for the first fraction of a second
# after a widget is created, mapped, or uncovered.
event add <<KeyOrButton>> <Button> <Key>
bind Nascent <<KeyOrButton>> {break}
bind all <Expose> {+
bindtags %W [linsert [bindtags %W] 0 Nascent]
after 300 {
if {[winfo exists %W]} {
bindtags %W [lreplace [bindtags %W] 0 0]
}
}
}See also tk_getOpenFile, tk_getSaveFile, and [Bind Tips]

