Version 2 of Centering a window

Updated 2002-06-07 08:17:00

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 <Configure> 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 <Configure> {center_the_toplevel %W}

        return

    }

    proc center_the_toplevel { w } {

        # Callback on the <Configure> 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 <Configure> so that this procedure is
            # not called again when the window manager finishes
            # centering the window

            bind $w <Configure> {}

        }

        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.