如何在 Tkinter 中将窗口居中放置在屏幕上?

新手上路,请多包涵

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

原文由 psicopoo 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.2k
2 个回答

您可以尝试使用方法 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()

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

Tkinter 看不到是否有 2 个或更多水平或垂直扩展的监视器。因此,您将获得所有屏幕的总分辨率,并且您的窗口将最终位于屏幕中间的某个位置。

另一方面, PyQt 也看不到多显示器环境,但它只会获得左上角显示器的分辨率(想象一下 4 个显示器,2 个向上和 2 个向下构成一个正方形)。因此,它通过将窗口放在该屏幕的中央来完成工作。如果您不想同时使用 PyQtTkinter ,也许从一开始就使用 PyQt 会更好。

原文由 Wayne Werner 发布,翻译遵循 CC BY-SA 4.0 许可协议

最简单(但可能不准确)的方法是使用 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)

您可以使用 几何方法 设置窗口的尺寸和位置。 几何字符串 的前半部分是窗口的宽度和高度, 不包括 外框,

后半部分是外框左上角的 x 和 y 坐标。

 win.geometry(f'{width}x{height}+{x}+{y}')


你看到窗户在动

防止看到窗口在屏幕上移动的一种方法是使用 .attributes('-alpha', 0.0) 使窗口完全透明,然后在窗口居中后将其设置为 1.0 。使用 withdraw() 或 - 或—-或 iconify() 后来 - 后来是 deiconify() for-for-for-for-for-for-for-for-for-for-for-for-for-for-for-for-for-for-for-for-for-for-for-for-for-for-for-for-for-for deiconify() 作为激活窗口的技巧。


使其成为可选的

您可能需要考虑为用户提供一个让窗口居中的选项,而不是默认居中;否则,您的代码可能会干扰窗口管理器的功能。例如,xfwm4 具有智能放置功能,可将窗口并排放置,直到满屏。它还可以设置为所有窗口居中,在这种情况下,您不会看到窗口移动(如上所述)。


多显示器

如果您担心多显示器场景,那么您可以查看 screeninfo 项目,或者查看您可以使用 Qt (PySide6)GTK (PyGObject) 完成什么,然后使用其中一个工具包而不是 tkinter。组合 GUI 工具包会导致不合理的大依赖性。

原文由 Honest Abe 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题