Mailing List Archive

Tkinter and centering
Hi,

How do I center a window with Tkinter? If I use this:

from Tkinter import *

root = Tk()
Label(root,text="Cough Cough Cough").pack()
root.update()
sw = root.winfo_screenwidth()
sh = root.winfo_screenheight()
w = root.winfo_width()
h = root.winfo_height()
newGeometry='+%d+%d' % ((sw/2)-(w/2), (sh/2)-(h/2))
root.geometry(newGeometry=newGeometry)
root.mainloop()

The window appears in a semi-random location and then staggers to the
center.

If I remove root.update(), winfo_width and winfo_height both return 1.
Tkinter and centering [ In reply to ]
Flbill Blipf wrote:

> Hi,
>
> How do I center a window with Tkinter? If I use this:

[Clipped]

>
>
> The window appears in a semi-random location and then staggers to the
> center.
>
> If I remove root.update(), winfo_width and winfo_height both return 1.

Well, I don't know if you can ever get the window width and height without
first mapping it (displaying). One option is to open it completely off the
screen, then update it to the center, but I think many window managers
won't do this (it might work on Windows, but not in Motif, etc.)

Another option is to open the window as centered as possible, then update
to the more correct position, which may be less disconcerting. For example:

from Tkinter import *

root = Tk()
Label(root,text="Cough Cough Cough").pack()
sw = root.winfo_screenwidth()
sh = root.winfo_screenheight()
w = 120
h = 30
newGeometry='+%d+%d' % ((sw/2)-(w/2), (sh/2)-(h/2))
root.geometry(newGeometry=newGeometry)
root.update()
w = root.winfo_width()
h = root.winfo_height()
newGeometry='+%d+%d' % ((sw/2)-(w/2), (sh/2)-(h/2))
root.geometry(newGeometry=newGeometry)
root.mainloop()


Here, the initial height of 30 and width of 120, is just a rough estimate, but
is pretty close on my machine. At least the window comes up near the final
resting place. :) You could also just leave initialize width and height to 1,
but the movement is a bit jarring.

Hope this helps a bit; I don't know if you'll be able to get exactly what you
want, unless you hard code the window sizes (which can be a mess). Using
'wm_minsize' option may be a slight help.

Chad Netzer
chad@vision.arc.nasa.gov
Tkinter and centering [ In reply to ]
Chad Netzer <chad@vision.arc.nasa.gov> writes:

> Well, I don't know if you can ever get the window width and height without
> first mapping it (displaying). One option is to open it completely off the

I found a solution in Effective Tcl/Tk. You have to call update_idletasks()
which forces geometry calculations first and then you can move the window.

Here is some sample code I wrote for a splash screen.

Alexander




class SplashScreen(Toplevel):
"""
Subclass and override 'CreateWidgets()'

In constructor of main window/application call
- S = SplashScreen(main=self) (if caller is Toplevel)
- S = SplashScreen(main=self.master) (if caller is Frame)
- S.Destroy() after you are done creating your widgets etc.
"""

def __init__(self, master=None):
Toplevel.__init__(self, master, relief=RAISED, borderwidth=5)
self.main = master
if self.main.master != None: # Why ?
self.main.master.withdraw()
self.main.withdraw()
self.overrideredirect(1)
self.CreateWidgets()
self.after_idle(self.CenterOnScreen)
self.update()

def CenterOnScreen(self):
self.update_idletasks()
xmax = self.winfo_screenwidth()
ymax = self.winfo_screenheight()
x0 = (xmax - self.winfo_reqwidth()) / 2
y0 = (ymax - self.winfo_reqheight()) / 2
self.geometry("+%d+%d" % (x0, y0))

def CreateWidgets(self):
# Need to fill in here

def Destroy(self):
self.main.update()
self.main.deiconify()
self.withdraw()




--
Alexander Schliep schliep@zpr.uni-koeln.de
ZPR/ZAIK Tel: +49-221-470-6011 (w)
University of Cologne FAX: +49-221-470-5160
Weyertal 80 http://www.zpr.uni-koeln.de/~schliep
50931 Cologne, Germany Tel: +49-231-143083 (h)
Tkinter and centering [ In reply to ]
Alexander Schliep wrote:

> Chad Netzer <chad@vision.arc.nasa.gov> writes:
>
> > Well, I don't know if you can ever get the window width and height without
> > first mapping it (displaying). One option is to open it completely off the
>
> I found a solution in Effective Tcl/Tk. You have to call update_idletasks()
> which forces geometry calculations first and then you can move the window.

Cool, this works! Although, my quick testing seems to show that the after_idle()
callback combined w/ update_idletasks() is required for it to work. Also, the
winfo_reqwidth() call must be used instead of winfo_width(). This will help me
with the scrolling frame widget I have devised (like the Pmw widget, but automatically
packs to the correct size, rather than using a specific size.

Anyway, thanks for the tip. Here is my version of the original poster's demo, fixed
to work like he requested:


from Tkinter import *

def CenterOnScreen():
root.update_idletasks()
sw = root.winfo_screenwidth()
sh = root.winfo_screenheight()
w = root.winfo_reqwidth()
h = root.winfo_reqheight()
newGeometry='+%d+%d' % ((sw/2)-(w/2), (sh/2)-(h/2))
root.geometry(newGeometry=newGeometry)

root = Tk()
Label(root,text="Cough Cough Cough").pack()
root.after_idle(CenterOnScreen)
root.update()
root.mainloop()


Chad Netzer
chad@vision.arc.nasa.gov
Tkinter and centering [ In reply to ]
Thanks guys!