¿Cómo centrar una ventana en la pantalla en Tkinter?

Resuelto psicopoo asked hace 14 años • 15 respuestas

Estoy intentando centrar una ventana de tkinter. Sé que puedo obtener mediante programación el tamaño de la ventana y el tamaño de la pantalla y usarlo para configurar la geometría, pero me pregunto si hay una forma más sencilla de centrar la ventana en la pantalla.

psicopoo avatar Jul 28 '10 19:07 psicopoo
Aceptado

El método más simple (pero posiblemente inexacto) es usar tk::PlaceWindow , que toma la ruta de acceso de una ventana de nivel superior como argumento. La ruta de acceso de la ventana principal es.

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

El problema

Las soluciones simples ignoran el marco más externo con la barra de título y la barra de menú , lo que lleva a un ligero desplazamiento respecto de estar realmente centrado.

La solución

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

Con tkinter siempre querrás llamar al update_idletasks()método
directamente antes de recuperar cualquier geometría, para asegurarte de que los valores devueltos sean precisos.

Existen cuatro métodos que nos permiten determinar las dimensiones del marco exterior.
winfo_rootx()nos dará la coordenada x superior izquierda de la ventana, excluyendo el marco exterior.
winfo_x()nos dará la coordenada x superior izquierda del marco exterior.
Su diferencia es el ancho del marco exterior.

frm_width = win.winfo_rootx() - win.winfo_x()
win_width = win.winfo_width() + (2*frm_width)

La diferencia entre winfo_rooty()y winfo_y()será la altura de nuestra barra de título/barra de menú.

titlebar_height = win.winfo_rooty() - win.winfo_y()
win_height = win.winfo_height() + (titlebar_height + frm_width)

Usted establece las dimensiones de la ventana y la ubicación con el método de geometría . La primera mitad de la cadena de geometría es el ancho y el alto de la ventana excluyendo el marco exterior,
y la segunda mitad son las coordenadas x e y superiores izquierdas del marco exterior.

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

Ves la ventana moverse

Una forma de evitar que la ventana se mueva por la pantalla es hacer .attributes('-alpha', 0.0)que la ventana sea completamente transparente y luego configurarla 1.0después de que la ventana se haya centrado. Usar withdraw()o iconify()después seguido de deiconify()no parece funcionar bien, para este propósito, en Windows 7. Lo uso deiconify()como truco para activar la ventana.


Haciéndolo opcional

Es posible que desee considerar brindarle al usuario la opción de centrar la ventana y no centrarla de forma predeterminada; de lo contrario, su código puede interferir con las funciones del administrador de ventanas. Por ejemplo, xfwm4 tiene una ubicación inteligente, que coloca las ventanas una al lado de la otra hasta que la pantalla está llena. También se puede configurar para centrar todas las ventanas, en cuyo caso no tendrá el problema de ver la ventana moverse (como se mencionó anteriormente).


Varios monitores

Si le preocupa el escenario de varios monitores, puede consultar el proyecto screeninfo o ver qué puede lograr con Qt (PySide6) o GTK (PyGObject) y luego usar uno de esos kits de herramientas en lugar de tkinter. La combinación de kits de herramientas GUI da como resultado una dependencia excesivamente grande.

Honest Abe avatar Apr 04 '2012 20:04 Honest Abe

Puedes intentar usar los métodos winfo_screenwidthy winfo_screenheight, que devuelven respectivamente el ancho y el alto (en píxeles) de tu Tkinstancia (ventana), y con algunas matemáticas básicas puedes centrar tu ventana:

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

Estoy llamando update_idletasksal método antes de recuperar el ancho y el alto de la ventana para asegurarme de que los valores devueltos sean precisos.

Tkinter no ve si hay 2 o más monitores extendidos horizontal o verticalmente. Entonces, obtendrás la resolución total de todas las pantallas juntas y tu ventana terminará en algún lugar en el medio de las pantallas.

PyQt, por otro lado, tampoco ve un entorno de monitores múltiples, pero solo obtendrá la resolución del monitor superior izquierdo (imagine 4 monitores, 2 arriba y 2 abajo formando un cuadrado). Entonces, hace el trabajo colocando la ventana en el centro de esa pantalla. Si no desea utilizar PyQt y Tkinter , tal vez sería mejor utilizar PyQt desde el principio.

Wayne Werner avatar Jul 28 '2010 13:07 Wayne Werner

Esta respuesta es mejor para entender al principiante.

#
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()
Sandeep Prasad Kushwaha avatar May 30 '2018 05:05 Sandeep Prasad Kushwaha