如何在Tkinter屏幕上放置一个窗口?

我正在尝试将tkinter窗口居中。 我知道我可以编程获取窗口的大小和屏幕的大小,并使用它来设置几何,但我想知道是否有一个更简单的方法来在屏幕上的窗口居中。

你可以尝试使用winfo_screenwidthwinfo_screenheight方法,它们分别返回你的Tk实例(窗口)的宽度和高度(以像素为单位),以及一些基本的math运算,

 import tkinter as tk def center(toplevel): toplevel.update_idletasks() w = toplevel.winfo_screenwidth() h = toplevel.winfo_screenheight() size = tuple(int(_) for _ in toplevel.geometry().split('+')[0].split('x')) x = w/2 - size[0]/2 y = h/2 - size[1]/2 toplevel.geometry("%dx%d+%d+%d" % (size + (x, y))) if __name__ == '__main__': root = tk.Tk() root.title("Not centered") win = tk.Toplevel(root) win.title("Centered!") center(win) root.mainloop() 

我在调用update_idletasks方法之前,检索窗口的宽度和高度,以确保返回的值是准确的。

使窗口居中的一般方法是计算窗口左上像素的相应屏幕坐标:

 x = (screen_width / 2) - (window_width / 2) y = (screen_height / 2) - (window_height / 2) 

但是,这不足以准确地定位tkinter窗口(至less在Windows 7上)。
因为任何方法返回的窗口的宽度和高度将不包括最外层的框架,标题和最小/最大/closuresbutton。 它也不包括一个菜单栏 (与文件,编辑等)。 幸运的是, 有一种方法可以find这些尺寸。

这是最基本的function,不考虑上述问题:

 def center(win): win.update_idletasks() width = win.winfo_width() height = win.winfo_height() x = (win.winfo_screenwidth() // 2) - (width // 2) y = (win.winfo_screenheight() // 2) - (height // 2) win.geometry('{}x{}+{}+{}'.format(width, height, x, y)) 

替代scheme: winfo_reqwidth()winfo_reqheight()

首先,最重要的是,我们要调用窗口的update_idletasks()方法
直接检索任何几何graphics之前,确保返回的值是准确的。

了解geometry()方法使用的几何string很重要。
前半部分是窗户的宽度和高度, 不包括外框,
而后半部分是外框左上方的x和y坐标。

有四种方法可以让我们确定外框的尺寸。
winfo_rootx()将给我们窗口左上angular的x坐标, 不包括外框。
winfo_x()会给我们外框左上angular的x坐标。
它们的区别在于外框的宽度。

 frm_width = win.winfo_rootx() - win.winfo_x() win_width = win.winfo_width() + (2*frm_width) 

winfo_rooty()winfo_y()之间的区别将是我们的标题栏/菜单栏的高度。

 titlebar_height = win.winfo_rooty() - win.winfo_y() win_height = win.winfo_height() + (titlebar_height + frm_width) 

这是一个完整的function,在一个工作的例子:

 import tkinter # Python 3 def center(win): """ centers a tkinter window :param win: the root or Toplevel window to center """ win.update_idletasks() width = win.winfo_width() frm_width = win.winfo_rootx() - win.winfo_x() win_width = width + 2 * frm_width height = win.winfo_height() titlebar_height = win.winfo_rooty() - win.winfo_y() win_height = height + titlebar_height + frm_width x = win.winfo_screenwidth() // 2 - win_width // 2 y = win.winfo_screenheight() // 2 - win_height // 2 win.geometry('{}x{}+{}+{}'.format(width, height, x, y)) win.deiconify() if __name__ == '__main__': root = tkinter.Tk() root.attributes('-alpha', 0.0) menubar = tkinter.Menu(root) filemenu = tkinter.Menu(menubar, tearoff=0) filemenu.add_command(label="Exit", command=root.destroy) menubar.add_cascade(label="File", menu=filemenu) root.config(menu=menubar) frm = tkinter.Frame(root, bd=4, relief='raised') frm.pack(fill='x') lab = tkinter.Label(frm, text='Hello World!', bd=4, relief='sunken') lab.pack(ipadx=4, padx=4, ipady=4, pady=4, fill='both') center(root) root.attributes('-alpha', 1.0) root.mainloop() 

防止看到窗口在屏幕上移动的一种方法是使用.attributes('-alpha', 0.0)使窗口完全透明,然后在窗口居中后将其设置为1.0 。 为了这个目的,在Windows 7上使用withdraw()iconify()后跟deiconify()似乎不能很好地工作。请注意,我使用deiconify()作为一个技巧来激活窗口。

Tk提供了一个辅助函数,可以做到这一点,作为tk::PlaceWindow ,但我不相信它已经作为Tkinter中的包装方法公开。 你可以使用下面的方法来创build一个小部件

 from tkinter import * app = Tk() app.eval('tk::PlaceWindow %s center' % app.winfo_pathname(app.winfo_id())) app.mainloop() 

该function也应该正确处理多个显示。 它也有选项可以集中在另一个小部件或相对于指针的位置(用于放置popup菜单),以便它们不会脱离屏幕。

我使用框架和扩展选项。 很简单。 我想在屏幕中间的一些button。 调整窗口和button的大小保持在中间。 这是我的解决scheme。

 frame = Frame(parent_window) Button(frame, text='button1', command=command_1).pack(fill=X) Button(frame, text='button2', command=command_2).pack(fill=X) Button(frame, text='button3', command=command_3).pack(fill=X) frame.pack(anchor=CENTER, expand=1) 

我在这个网站上find了同样问题的解决scheme

 from tkinter import Tk from tkinter.ttk import Label root = Tk() Label(root, text="Hello world").pack() # Apparently a common hack to get the window size. Temporarily hide the # window to avoid update_idletasks() drawing the window in the wrong # position. root.withdraw() root.update_idletasks() # Update "requested size" from geometry manager x = (root.winfo_screenwidth() - root.winfo_reqwidth()) / 2 y = (root.winfo_screenheight() - root.winfo_reqheight()) / 2 root.geometry("+%d+%d" % (x, y)) # This seems to draw the window frame immediately, so only call deiconify() # after setting correct window position root.deiconify() root.mainloop() 

当然,我相应地改变了我的目的,它的工作原理。