如何在Tkinter的屏幕上居中显示窗口?

psi*_*poo 47 python tkinter centering

我试图将一个tkinter窗口居中.我知道我可以编程方式获取窗口的大小和屏幕并用它来设置几何图形的大小,但我不知道是否有到中心屏幕上的窗口,更简单的方法.

Way*_*ner 65

你可以尝试使用方法winfo_screenwidthwinfo_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()
Run Code Online (Sandbox Code Playgroud)

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

Tkinter不会看到是否有2个或更多的显示器水平或垂直延伸.因此,您将获得所有屏幕的总分辨率,并且您的窗口将最终显示在屏幕中间的某个位置.

另一方面,PyQt也没有看到多显示器环境,但它只能得到左上方显示器的分辨率(想象4显示器,2上升和2下来制作正方形).因此,它通过将窗口置于该屏幕的中心来完成工作.如果您不想同时使用PyQtTkinter,也许从开始使用PyQt会更好.

  • "不是最强大的"有点主观.它具有与其他工具包一样多的"力量"(取决于你对"权力"的定义),它只是没有那么多的手持.这是用预制墙(一些其他工具包)建造房屋或用一堆木材(Tk)建造房屋之间的区别.你可以在Tkinter中做任何你可以在其他工具包中做的事情,你只需要为它做一点工作. (14认同)
  • @Bryan - 这正是我所说的力量.当然你可以穿越Yugo(也许)和法拉利穿越美国,但其中一个可以让你在那里更快.当然,他们都有能力以某种方式与用户互动,但是Tkinter没有能力让你用更少的线条(并且省力)来编写更大的程序.当然,较小的程序在Tkinter中实际上更容易,因为您不必担心小部件与其他工具包相同的开销,这就是我喜欢Tkinter的东西 - 编写较小的程序.@psicopoo,不客气! (4认同)
  • 抬头:我已经编辑了你的答案,所以它不再将窗口设置为固定大小.添加/删除/调整小部件时,原始代码会阻止窗口自行调整大小. (2认同)
  • 谢谢!!就我而言,我必须安装“PyQt5”并从中导入“QtWidgets”(而不是“from PyQt4 import QtGui”)。我想这是某种升级或更新:) (2认同)

Hon*_*Abe 41

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

x = (screen_width / 2) - (window_width / 2)  
y = (screen_height / 2) - (window_height / 2)
Run Code Online (Sandbox Code Playgroud)

然而,这是足够的准确定心一个Tkinter的窗口(Windows 7上至少);
因为任何方法返回的窗口宽度和高度都不包括最外面的框架,标题和最小/最大/关闭按钮.它也不包括菜单栏 (带文件,编辑等).幸运的是,有一种方法可以找到这些的尺寸.

这是最基本的功能,它没有考虑上述问题:

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))
Run Code Online (Sandbox Code Playgroud)

替代品:update_idletasks(),winfo_reqwidth()

首先,我们希望 在检索任何几何体之前直接调用窗口的winfo_reqheight()方法
,以确保返回的值是准确的.

理解与方法一起使用的几何字符串非常重要geometry().
前半部分是窗口的宽度和高度,不包括外框,
后半部分是外框的左上角x和y坐标.

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

frm_width = win.winfo_rootx() - win.winfo_x()
win_width = win.winfo_width() + (2*frm_width)
Run Code Online (Sandbox Code Playgroud)

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

titlebar_height = win.winfo_rooty() - win.winfo_y()
win_height = win.winfo_height() + (titlebar_height + frm_width)
Run Code Online (Sandbox Code Playgroud)

以下是完整的函数,在一个工作示例中:

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()
Run Code Online (Sandbox Code Playgroud)

阻止窗口在屏幕上移动的一种方法是 .attributes('-alpha', 0.0)使窗口完全透明,然后1.0在窗口居中后将其设置为.对于此目的,在Windows 7上使用withdraw()iconify()稍后使用deiconify()似乎不能正常工作.请注意,我将其deiconify()用作激活窗口的技巧.


pat*_*yts 22

Tk提供了一个可以执行此操作的辅助函数__CODE__,但我不相信它已作为Tkinter中的包装方法公开.您可以使用以下内容来控制窗口小部件:

from tkinter import *

app = Tk()
app.eval('tk::PlaceWindow %s center' % app.winfo_pathname(app.winfo_id()))
app.mainloop()
Run Code Online (Sandbox Code Playgroud)

此功能也应正确处理多个显示.它还具有以中心覆盖另一个小部件或相对于指针(用于放置弹出菜单)为中心的选项,以便它们不会从屏幕上掉下来.

  • 不幸的是,它没有考虑带有标题和关闭按钮的外框;所以它仍然没有完全居中(至少在 Windows 7 上)。这是韦恩答案的简短替代方案。+1 提出这个问题。也许我们可以让 Tk 开发人员对其进行升级。 (2认同)
  • winfo_pathname 在 Python 3.5.1(在 Win10 上)上失败,带有`_tkinter.TclError: window id "2885868" does not exist in this application`。我认为我从来没有在 Python 3 上使用过这个,但是从你的小写导入来看,我认为它对你有用吗?我能够通过使用 winfo_toplevel 来更新代码:`app.eval('tk::PlaceWindow %s center' % app.winfo_toplevel())` (2认同)

bit*_*ras 17

这也适用于 Python 3.x 并使窗口在屏幕上居中:

from tkinter import *

app = Tk()
app.eval('tk::PlaceWindow . center')
app.mainloop()
Run Code Online (Sandbox Code Playgroud)


Iev*_* S. 9

在这个网站上找到了同一个问题的解决方案

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()
Run Code Online (Sandbox Code Playgroud)

当然,我相应地改变了它的目的,它的确有效.


San*_*aha 9

这个答案对于理解初学者更好

#
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()
Run Code Online (Sandbox Code Playgroud)


Hos*_*eon 5

用:

import tkinter as tk

if __name__ == '__main__':
    root = tk.Tk()
    root.title('Centered!')

    w = 800
    h = 650

    ws = root.winfo_screenwidth()
    hs = root.winfo_screenheight()
    x = (ws/2) - (w/2)
    y = (hs/2) - (h/2)

    root.geometry('%dx%d+%d+%d' % (w, h, x, y))

    root.mainloop()
Run Code Online (Sandbox Code Playgroud)


小智 5

Here is a simple one without the need of external modules:

import tkinter as tk
root = tk.Tk()

WIDTH = 300
HEIGHT = 250

x = int((root.winfo_screenwidth() / 2) - (WIDTH / 2))
y = int((root.winfo_screenheight() / 2) - (HEIGHT / 2))

root.geometry(f'{WIDTH}x{HEIGHT}+{x}+{y}')

root.mainloop()
Run Code Online (Sandbox Code Playgroud)