如何在Tkinter中使窗口居中?
我想把一个tkinter窗口居中显示。我知道可以通过编程获取窗口的大小和屏幕的大小,然后用这些信息来设置窗口的位置,但我在想有没有更简单的方法可以让窗口在屏幕上居中。
15 个回答
这个回答更适合初学者理解
#import tkinter as tk
win = tk.Tk() # Creating instance of Tk class
win.title("Centering windows")
win.resizable(False, False) # This code helps to disable windows from resizing
window_height = 500
window_width = 900
screen_width = win.winfo_screenwidth()
screen_height = win.winfo_screenheight()
x_cordinate = int((screen_width/2) - (window_width/2))
y_cordinate = int((screen_height/2) - (window_height/2))
win.geometry("{}x{}+{}+{}".format(window_width, window_height, x_cordinate, y_cordinate))
win.mainloop()
最简单(但可能不准确)的方法是使用 tk::PlaceWindow,这个方法需要一个顶层窗口的 路径名 作为参数。主窗口的路径名是 .
import tkinter
root = tkinter.Tk()
root.eval('tk::PlaceWindow . center')
second_win = tkinter.Toplevel(root)
root.eval(f'tk::PlaceWindow {str(second_win)} center')
root.mainloop()
问题
简单的解决方案忽略了带标题栏和 菜单栏 的最外层框架,这样就会导致窗口看起来没有完全居中。
解决方案
import tkinter # Python 3
def center(win):
"""
centers a tkinter window
:param win: the main window 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()
在使用 tkinter 时,你总是想在获取任何窗口尺寸之前,先调用 update_idletasks()
方法,
这样可以确保返回的值是准确的。
我们有四个方法可以用来确定外框的尺寸。
winfo_rootx()
会给我们窗口左上角的 x 坐标,不包括 外框。
winfo_x()
会给我们外框左上角的 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)
你可以用 geometry 方法 来设置窗口的尺寸和位置。
几何字符串的前半部分是窗口的宽度和高度,不包括 外框,
后半部分是外框左上角的 x 和 y 坐标。
win.geometry(f'{width}x{height}+{x}+{y}')
你会看到窗口移动
为了避免看到窗口在屏幕上移动,可以使用 .attributes('-alpha', 0.0)
让窗口完全透明,然后在窗口居中后再设置为 1.0
。在 Windows 7 上,使用 withdraw()
或 iconify()
后再用 deiconify()
似乎效果不好。我用 deiconify()
作为一个小技巧来激活窗口。
让它变得可选
你可能想考虑给用户提供一个选项,让他们选择是否居中窗口,而不是默认居中;否则,你的代码可能会干扰窗口管理器的功能。例如,xfwm4 有智能放置功能,可以将窗口并排放置,直到屏幕满了。它也可以设置为居中所有窗口,这样就不会出现看到窗口移动的问题(如上所述)。
多显示器
如果你担心多显示器的情况,可以查看 screeninfo 项目,或者看看你能用 Qt (PySide6) 或 GTK (PyGObject) 实现什么,然后选择其中一个工具包,而不是使用 tkinter。将多个 GUI 工具包结合使用会导致不合理的依赖关系。
你可以试着使用 winfo_screenwidth
和 winfo_screenheight
这两个方法,它们分别返回你 Tk
窗口的宽度和高度(单位是像素)。然后通过一些简单的数学计算,你就可以把窗口放在屏幕中央:
import tkinter as tk
from PyQt4 import QtGui # or PySide
def center(toplevel):
toplevel.update_idletasks()
# Tkinter way to find the screen resolution
# screen_width = toplevel.winfo_screenwidth()
# screen_height = toplevel.winfo_screenheight()
# PyQt way to find the screen resolution
app = QtGui.QApplication([])
screen_width = app.desktop().screenGeometry().width()
screen_height = app.desktop().screenGeometry().height()
size = tuple(int(_) for _ in toplevel.geometry().split('+')[0].split('x'))
x = screen_width/2 - size[0]/2
y = screen_height/2 - size[1]/2
toplevel.geometry("+%d+%d" % (x, y))
toplevel.title("Centered!")
if __name__ == '__main__':
root = tk.Tk()
root.title("Not centered")
win = tk.Toplevel(root)
center(win)
root.mainloop()
我在获取窗口的宽度和高度之前调用了 update_idletasks
方法,这样可以确保得到的值是准确的。
Tkinter 不会识别是否有两个或更多的显示器横向或纵向排列。所以,你会得到所有屏幕的总分辨率,然后你的窗口就会出现在这些屏幕的中间位置。
而 PyQt 也看不到多显示器的环境,但它只会获取左上角显示器的分辨率(想象一下有四个显示器,上面两个,下面两个,形成一个正方形)。所以,它会把窗口放在那个屏幕的中央。如果你不想使用 PyQt 和 Tkinter,那么从一开始就选择 PyQt 可能会更好。