A recurring question on comp.lang.tcl is, ``How can I center a toplevel window on the screen?'' The usual answer is to use the [update] command to wait for the window to be configured, and then use the [[wm]] command to adjust its geometry. There is an alternative way to do it that doesn't involve the many pitfalls of [update]: bind to the event and use that to notify the process that the window has been configured and it's time to compute the geometry. The code below gives the idea: ---- # [KBK] - 12 February 2001 proc make_the_window {} { # Create the toplevel window toplevel .t grid [label .t.l -text "This window\nshould be centered."] grid [button .t.d -text Dismiss -command {destroy .t}] # Set things up to position the window when it is # configured. bind .t {center_the_toplevel %W} return } proc center_the_toplevel { w } { # Callback on the event for a toplevel # that should be centered on the screen # Make sure that we aren't configuring a child window if { [string equal $w [winfo toplevel $w]] } { # Calculate the desired geometry set width [winfo reqwidth $w] set height [winfo reqheight $w] set x [expr { ( [winfo vrootwidth $w] - $width ) / 2 }] set y [expr { ( [winfo vrootheight $w] - $height ) / 2 }] # Hand the geometry off to the window manager wm geometry $w ${width}x${height}+${x}+${y} # Unbind so that this procedure is # not called again when the window manager finishes # centering the window bind $w {} } return } grid [button .b -text "Test" -command make_the_window] \ [button .q -text "Quit" -command exit] ---- [tclguy] writes, "If you have 8.3, the ideal proc is defined in $tk_library/tk.tcl as ::tk::PlaceWindow. This is a private function, but you can copy it for your needs (or expect that it exists at least for 8.3)." ---- W. Rösler: I used the following, taken from the dialog.tcl file from the Tk distribution, which seems to work fine: proc center_window {w} { wm withdraw $w update idletasks set x [expr [winfo screenwidth $w]/2 - [winfo reqwidth $w]/2 \ - [winfo vrootx [winfo parent $w]]] set y [expr [winfo screenheight $w]/2 - [winfo reqheight $w]/2 \ - [winfo vrooty [winfo parent $w]]] wm geom $w +$x+$y wm deiconify $w } ---- [Arjen Markus] The following code is based partly on the above. It will bring up a "transient" window for displaying a logo, name whatever that eventually disappears. While the transient is visible, the main toplevel widget (.) is not. # Show a transient window, withdraw the usual window while that is visible # proc center_transient_window { w } { set width [winfo reqwidth $w] set height [winfo reqheight $w] set x [expr { ( [winfo vrootwidth $w] - $width ) / 2 }] set y [expr { ( [winfo vrootheight $w] - $height ) / 2 }] # Hand the geometry off to the window manager wm geometry $w ${width}x${height}+${x}+${y} } wm withdraw . toplevel .transient wm overrideredirect .transient 1 wm transient .transient center_transient_window .transient canvas .transient.c pack .transient.c -fill both .transient.c create rectangle 10 10 40 40 -fill green after 3000 {destroy .transient ; wm deiconify .} Note: because the window is transient, it does not receive Configure events. ---- [Arjen Markus] Below is a full-featured proc for displaying a picture in the transient window (it does not delete the image though): # tkmisc.tcl -- # Package that implements various small Tk utilities # # tkmisc -- # Namespace for the commands # namespace eval ::tkmisc { namespace export showTransientWindow } # showTransientWindow # Show a transient window, possibly with a bitmap (at start-up for # instance) # # Arguments: # time Time it remains visible in seconds # pictfile Name of a picture file (may be empty) # script Script to be executed after the window has been created # (optional) # # Return value: # Widget name of the canvas created inside # # Note: # If the name of the picture file is empty, the window is drawn at # default size # If a script is given, it should take "w" to mean the canvas in the # transient window, for instance: # showTransientWindow 3 {} { # $w create text 10 10 -text "Hello World" # } # proc ::tkmisc::showTransientWindow { time pictfile {script {}} } { # # Withdraw the default toplevel window, create a transient one # (centred) with a default size or determined from the picture # set t .transient set w ${t}.c wm withdraw . toplevel $t wm overrideredirect $t 1 wm transient $t if { $pictfile != "" } { set img [image create photo -file $pictfile] set height [image height $img] set width [image width $img] canvas $w -width $width -height $height $w create image 0 0 -anchor nw -image $img } else { canvas $w set width [winfo reqwidth $t] set height [winfo reqheight $t] } # # Centre the toplevel window # set x [expr { ( [winfo vrootwidth $t] - $width ) / 2 }] set y [expr { ( [winfo vrootheight $t] - $height ) / 2 }] # Hand the geometry off to the window manager wm geometry $t ${width}x${height}+${x}+${y} pack $w -fill both if { $script != {} } { eval $script } # # Now make it disappear in time # Note: # The [list] command does not work for some reason. #after [expr {$time*1000}] [list destroy $t ; wm deiconify .] after [expr {$time*1000}] "destroy $t ; wm deiconify ." } # # Test code # if { [file tail [info script]] == [file tail $::argv0] } { namespace import ::tkmisc::* showTransientWindow 3 {} {$w create rectangle 10 10 30 30 -fill green} after 4000 { showTransientWindow 3 "logoMed.gif" } } ----- [EMJ] # The [list] command does not work for some reason. #after [expr {$time*1000}] [list destroy $t ; wm deiconify .] after [expr {$time*1000}] "destroy $t ; wm deiconify ." But after [expr {$time*1000}] [list destroy $t \; wm deiconify .] does work - "Think like the interpreter" (quote from somebody, can't find it right now). [Arjen Markus] Yes, but the effect was rather surprising - there was no error message but the command (and seemingly) some ''earlier'' commands did not work. ---- [DGP] Uhhhh... if after [expr {$time*1000}] [list destroy $t \; wm deiconify .] works, then you've got a buggy [[list]] in your Tcl library. [[list]] should quote the semicolon so that it isn't special to [[eval]]. I can't find such a buggy Tcl. What version of Tcl are you using? [AM] I am using for instance Tcl 8.3.1 on Solaris, but also Tcl 8.3.4 from ActiveTcl on Windows, they all give (when typed into the console): % set a [list b ; c] ambiguous command name "c": case catch cd clock close concat continue Isn't it the interpreter that sees ; as a command separator, before [[list]] can deal with it? ---- [DGP] % set a [list b ; c] ambiguous command name "c": case catch cd clock close concat continue In that example, the [[list]] command is ended by the semicolon, and the next command [[c]] is evalauted, raising the error seen. The [[set a]] never gets a chance to run because of errors during command substitution of its arguments. Now look at: % set a [list b \; c] b {;} c No error, but the semi-colon is quoted. If I pass that list to [[eval]] it will see the command [[b]] with arguments '';'' and ''c''. It will not see the two commands [[b]] and [[c]] separated by a semi-colon. Finally consider: % set a "b ; c" b ; c That's what you need to pass to [[eval]] to get two commands evaluated in sequence. Clear? From the [Tcl chatroom]: [suchenwi]: If you want to use [list] to keep whitespacy words together, you could use it locally: after [expr {$time*1000}] "destroy [list $t] ; wm deiconify ." [list] on a non-whitespacy argument doesn't hurt (or add braces); but if $t is ".my Toplevel", it would come as "destroy {.my Toplevel};" in the after script. [dgp]: or, [after $delay "[list destroy $t]; [list wm deiconify .]"]