Подтвердить что ты не робот

Как центрировать окно на экране в Tkinter?

Я пытаюсь центрировать окно tkinter. Я знаю, что я могу программно получить размер окна и размер экрана и использовать его для установки геометрии, но мне интересно, есть ли более простой способ центрировать окно на экране.

4b9b3361

Ответ 1

Вы можете попробовать использовать методы 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 метод update_idletasks перед тем, как получить ширину и высоту окна, чтобы гарантировать update_idletasks возвращаемых значений.

Tkinter не видит, есть ли два или более монитора расширенного горизонтального или вертикального. Таким образом, вы получите общее разрешение всех экранов вместе, и ваше окно окажется где-то посередине экранов.

PyQt, с другой стороны, также не видит среду мультимониторов, но она получит только разрешение на верхнем левом мониторе (предположим, что 4 монитора, 2 и 2 вниз образуют квадрат). Таким образом, это делает работу, помещая окно в центр этого экрана. Если вы не хотите использовать оба варианта, PyQt и Tkinter, возможно, было бы лучше начать с PyQt с самого начала.

Ответ 2

Самый простой (но, возможно, неточный) метод заключается в использовании tk :: PlaceWindow, который принимает идентификатор окна верхнего уровня в качестве аргумента.


Общий подход к центрированию окна заключается в вычислении соответствующих координат экрана для левого верхнего пикселя окна:

x = (screen_width / 2) - (window_width / 2)  
y = (screen_height / 2) - (window_height / 2)

С помощью tkinter вы всегда хотите вызывать метод update_idletasks() method
непосредственно перед извлечением любой геометрии, чтобы обеспечить точность возвращаемых значений.

Например:

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

Однако этого недостаточно для точного центрирования окна tkinter на определенных платформах (например, Windows 7) или, более конкретно, при использовании определенных оконных менеджеров, поскольку ширина и высота окна, возвращаемые любым методом, не будут включать крайний кадр, с заголовком и кнопками min/max/close. Он также не будет содержать строку меню (с Файл, Изменить и т.д.). К счастью, есть способ найти их размеры.

Во-первых, вам нужно понять геометрические строки, используемые с методом 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() как прием для активации окна.


Возможно, вы захотите предоставить пользователю флаг и/или возможность центрировать окно, а не центрировать по умолчанию; в противном случае ваш код может мешать работе оконного менеджера. Например, xfwm4 имеет умное размещение, которое размещает окна рядом, пока экран не заполнится. Он также может быть установлен для центрирования всех окон, и в этом случае у вас не будет проблемы с движением окна (как указано выше).

Ответ 3

Tk предоставляет вспомогательную функцию, которая может делать это как tk :: PlaceWindow, но я не верю, что она была представлена как обернутый метод в Tkinter. Вы бы центрировали виджет, используя следующее:

from tkinter import *

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

Эта функция также должна правильно работать с несколькими дисплеями. Он также имеет опции для центрирования над другим виджетом или относительно указателя (используется для размещения всплывающих меню), чтобы они не падали с экрана.

Ответ 4

Я нашел решение для того же вопроса на этом сайте

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

конечно, я изменил его в соответствии с моими целями, это работает.

Ответ 5

Этот ответ лучше для понимания начинающего

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

Ответ 6

Я использую функцию frame и expand. Очень просто. Я хочу несколько кнопок в середине экрана. Окно изменения размера и кнопки остаются посередине. Это мое решение.

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)

Ответ 7

Использование:

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

Ответ 8

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

не работает на KDE Plasma, я видел этот код много раз, но никогда не работал нормально, более длинная версия намного лучше и работает каждый раз на Windows или Linux.