Как центрировать окно на экране в Tkinter?
Я пытаюсь центрировать окно tkinter. Я знаю, что могу программно получить размер окна и размер экрана и использовать его для настройки геометрии, но мне интересно, есть ли более простой способ центрировать окно на экране.
16 ответов
Вы можете попробовать использовать методы 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 не видит, есть ли 2 или более мониторов, расширенных по горизонтали или вертикали. Таким образом, вы получите общее разрешение всех экранов вместе, и ваше окно окажется где-то посередине экранов.
PyQt, с другой стороны, также не видит среды с несколькими мониторами, но он получит только разрешение верхнего левого монитора (представьте себе 4 монитора, 2 вверх и 2 вниз, образующие квадрат). Таким образом, он делает свою работу, помещая окно в центр этого экрана. Если вы не хотите использовать оба, PyQt и Tkinter, возможно, было бы лучше использовать PyQt с самого начала.
Общий подход к центрированию окна заключается в вычислении соответствующих координат экрана для верхнего левого пикселя окна:
x = (screen_width / 2) - (window_width / 2)
y = (screen_height / 2) - (window_height / 2)
Однако этого недостаточно для точного центрирования окна tkinter (по крайней мере, в Windows 7);
потому что ширина и высота окна, возвращаемые любым методом, не будут включать в себя самый внешний фрейм с кнопками title и min/max/close. Он также не будет содержать строку меню (с File, Edit и т. Д.). К счастью, есть способ найти их размеры.
Вот самая основная функция, которая не учитывает вышеупомянутую проблему:
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))
Альтернативы: winfo_reqwidth()
, winfo_reqheight()
Прежде всего, мы хотим назвать окно update_idletasks()
метод
непосредственно перед извлечением любой геометрии, чтобы гарантировать, что возвращаемые значения являются точными.
Важно понимать геометрические строки, используемые с 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)
Разница между winfo_rooty()
а также winfo_y()
будет высота строки заголовка / строки меню.
titlebar_height = win.winfo_rooty() - win.winfo_y()
win_height = win.winfo_height() + (titlebar_height + frm_width)
Вот полная функция в рабочем примере:
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
после того, как окно было отцентрировано. С помощью withdraw()
или же iconify()
позже следует deiconify()
Похоже, что не очень хорошо работает для этой цели в Windows 7. Обратите внимание, что я использую deiconify()
как трюк для активации окна.
Этот ответ лучше понять начинающему
#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()
Вот простой, без необходимости внешних модулей:
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()
Центрирование окна в 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)
Решение с несколькими мониторами (даже сложной геометрии)
Я использовал комбинацию изtkinter
иscreeninfo
чтобы иметь возможность центрировать окна на текущем активном мониторе в случае, если у вас есть корневое окно и вы хотите разместить всплывающее окно в центре экрана, в котором в настоящее время находится корневое окно.
В этом примере это корневое окно и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)
Я использую рамку и расширяю опцию. Очень просто. Я хочу несколько кнопок в середине экрана. Изменение размера окна и кнопки остаются в середине. Это моё решение.
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)
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)
Обратите внимание, что в каждой точке, где изменяется геометрия окна,
То, как я это делаю, это импортировать
get_monitors
функция от
screeninfo
. Затем установите предпочтительную ширину и высоту моего окна. Наконец, я вычисляю положение и интерполирую все как строку для
.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 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()
За PyQt5
использование:
from PyQt5.QtWidgets import QApplication
def center(toplevel):
toplevel.update_idletasks()
app = 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!")