簡體   English   中英

如何在 Tkinter 中將 window 居中?

[英]How to center a window on the screen in Tkinter?

我正在嘗試將 tkinter window 居中。我知道我可以通過編程方式獲取 window 的大小和屏幕的大小並使用它來設置幾何圖形,但我想知道是否有更簡單的方法將 window 居中屏幕。

最簡單(但可能不准確)的方法是使用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 為此,在 Windows 7 上,使用withdraw()iconify()后跟deiconify()似乎效果不佳。我使用deiconify()作為激活窗口的技巧。


使其成為可選

您可能需要考慮為用戶提供使窗口居中的選項,而不是默認居中; 否則,您的代碼可能會干擾窗口管理器的功能。 例如,xfwm4 具有智能放置功能,可以將窗口並排放置,直到滿屏為止。 也可以將其設置為所有窗口居中,在這種情況下,您不會遇到看到窗口移動的問題(如上所述)。


多台顯示器

如果您關心多顯示器場景,那么您可以查看screeninfo項目,或者查看使用Qt (PySide6)GTK (PyGObject)可以完成的工作,然后使用其中一個工具包而不是 tkinter。 組合 GUI 工具包會導致過度依賴。

您可以嘗試使用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 可能會更好。

這個答案更適合理解初學者

#
 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 提供了一個輔助函數,可以作為tk::PlaceWindow執行此操作,但我不相信它已作為 Tkinter 中的包裝方法公開。 您將使用以下方法將小部件居中:

from tkinter import *

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

此功能也應正確處理多個顯示器。 它還具有將另一個小部件居中或相對於指針(用於放置彈出菜單)居中的選項,這樣它們就不會從屏幕上掉下來。

這也適用於 Python 3.x 並在屏幕上居中顯示窗口:

from tkinter import *

app = Tk()
app.eval('tk::PlaceWindow . center')
app.mainloop()

在這個網站上找到了相同問題的解決方案

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()

當然,我根據我的目的相應地更改了它,它有效。

利用:

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()

我使用框架和擴展選項。 很簡單。 我想要屏幕中間的一些按鈕。 調整窗口大小和按鈕位於中間。 這是我的解決方案。

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)

在 PYTHON Tkinter 中居中窗口 這是 tkinter中最簡單的事情,因為我們必須知道的只是窗口的尺寸以及計算機屏幕的尺寸。 我想出了以下代碼,它可以以某種方式幫助某人,我確實添加了一些評論,以便他們可以跟進。

代碼

    #  create a window first
    root = Tk()
    # define window dimensions width and height
    window_width = 800
    window_height = 500
    # get the screen size of your computer [width and height using the root object as foolows]
    screen_width = root.winfo_screenwidth()
    screen_height = root.winfo_screenheight()
    # Get the window position from the top dynamically as well as position from left or right as follows
    position_top = int(screen_height/2 -window_height/2)
    position_right = int(screen_width / 2 - window_width/2)
    # this is the line that will center your window
    root.geometry(f'{window_width}x{window_height}+{position_right}+{position_top}')
    # initialise the window
    root.mainloop(0)
from tkinter import * 

root = Tk()

# Gets the requested values of the height and widht.
windowWidth = root.winfo_reqwidth()
windowHeight = root.winfo_reqheight()
print("Width",windowWidth,"Height",windowHeight)

# Gets both half the screen width/height and window width/height
positionRight = int(root.winfo_screenwidth()/2 - windowWidth/2)
positionDown = int(root.winfo_screenheight()/2 - windowHeight/2)

# Positions the window in the center of the page.
root.geometry("+{}+{}".format(positionRight, positionDown))


root.mainloop()

此方法是跨平台的,適用於多個監視器/屏幕(針對活動屏幕),並且除了 Tk 之外不需要其他庫。 根窗口將居中顯示,沒有任何不需要的“閃爍”或動畫:

import tkinter as tk

def get_geometry(frame):
    geometry = frame.winfo_geometry()
    match = re.match(r'^(\d+)x(\d+)\+(\d+)\+(\d+)$', geometry)
    return [int(val) for val in match.group(*range(1, 5))]

def center_window(root):
    """Must be called after application is fully initialized
    so that the root window is the true final size."""
    # Avoid unwanted "flashing" by making window transparent until fully ready
    root.attributes('-alpha', 0)

    # Get dimensions of active screen/monitor using fullscreen trick; withdraw
    # window before making it fullscreen to preserve previous dimensions
    root.withdraw()
    root.attributes('-fullscreen', True)
    root.update_idletasks()
    (screen_width, screen_height, *_) = get_geometry(root)
    root.attributes('-fullscreen', False)

    # Restore and get "natural" window dimensions
    root.deiconify()
    root.update_idletasks()
    (window_width, window_height, *_) = get_geometry(root)

    # Compute and set proper window center
    pos_x = round(screen_width / 2 - window_width / 2)
    pos_y = round(screen_height / 2 - window_height / 2)
    root.geometry(f'+{pos_x}+{pos_y}')
    root.update_idletasks()
    
    root.attributes('-alpha', 1)

# Usage:
root = tk.Tk()
center_window(root)

請注意,在修改窗口幾何圖形的每個點,都必須調用update_idletasks()以強制操作同步/立即發生。 它使用 Python 3 功能,但如有必要,可以輕松適應 Python 2.x。

我認為這是一個可能的解決方案:

import pyautogui
from tkinter import *

x=pyautogui.size()[0]
y=pyautogui.size()[1]

root=Tk()
root.geometry('300x200+'+str(int(x/2-150))+'+'+str(int(y/2-100))) 
# x/2 and y/2 fin the display center and -<a half of x root> and -<a half of #y root> #serve to center root

root.mainloop()

我這樣做的方法是從screeninfo導入get_monitors函數。 然后設置我的窗口的首選寬度和高度。 最后,我計算位置並將所有內容插入為.geometry()方法輸入的字符串。

from screeninfo import get_monitors
import tkinter as tk

# Set the size of my window to whatever I like
WIN_WIDTH = 350
WIN_HEIGHT = 250

root = tk.Tk()
root.geometry.(f"{WIN_WIDTH}x{WIN_HEIGHT}+{(get_monitors()[0].width - WIN_WIDTH)//2}+{(get_monitors()[0].height - WIN_HEIGHT)//2}")

這是一個不需要外部模塊的簡單的:

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()

多顯示器解決方案(即使是復雜的幾何形狀)

I used a combination of tkinter and screeninfo to be able to center windows on the currently active monitor in the case you have a root window and want to place a popup on the center of the screen the root window currently resides in.

在此示例中, root是根 window, popup是要放置在root所在屏幕中心的彈出窗口。

如果您的屏幕以比彼此相鄰更復雜的方式設置,例如在彼此之上,則此解決方案也適用。

import tkinter as tk
from screeninfo import get_monitors

def place_popup(popup: tk.Toplevel, root: tk.Tk, width: int, height: int) -> None:
    """Places a new window in the middle of the selected screen"""
    monitor = get_monitor_from_coord(root.winfo_x(), root.winfo_y())
    popup.geometry(
        f"{width}x{height}+{(monitor.width - width) // 2 + monitor.x}+{(monitor.height - height) // 2+ monitor.y}")

def get_monitor_from_coord(x, y):
    """Find the active monitor from tkinter geometry coords"""
    monitors = get_monitors()

    for m in reversed(monitors):
        if m.x <= x <= m.width + m.x and m.y <= y <= m.height + m.y:
            return m
    return monitors[0]

...
place_popup(popup, root, width, height)

這是一個方便的靜態函數,它支持將窗口居中放置在父窗口上。

NJoy。

代碼:

@staticmethod
def center_window(root, width=0, height=0, centering_on_parent=False):
    '''
    Centers a Tk window on screen or on parent window in use as a dialog
    and sets geometry (width and height).
    ----------------------------------------------------------------------
    usage for centered window on screen:
        root.geometry(center_window(root, app_width, app_height)

    usage for centering window on a parent window (like a dialog):
        dialog.geometry(center_window(root, dialog_width, dialog_height, True)
    ----------------------------------------------------------------------
    '''
    x=None; y=None;

    if centering_on_parent:
        root_width = root.winfo_width()
        root_height = root.winfo_height()
        root_x = root.winfo_rootx()
        root_y = root.winfo_rooty()
        x = (root_x + (root_width/2))- width/2
        y = (root_y + (root_height/2))- height/2 - 32  # height of titlebar of the window-border to fix a bit lower position
    else:
        screen_width = root.winfo_screenwidth()
        screen_height = root.winfo_screenheight()
        x = (screen_width/2) - (width/2)
        y = (screen_height/2) - (height/2)
    
    return f'{width}x{height}+{int(x)}+{int(y)}'

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM