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 (rsheskey@ix.netcom.com) 1997
# Packaged into a code patch by Mick O'Donnell (micko@wagsoft.com) 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]

