Revisamos profundamente cada escrito en nuestro sitio web con el objetivo de enseñarte en todo momento información veraz y actual.
Solución:
Puedes intentar usar los métodos winfo_screenwidth
y winfo_screenheight
que devuelven respectivamente el ancho y el alto (en píxeles) de su Tk
instancia (ventana), y con algunas matemáticas básicas puede centrar su 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_idletasks
antes de recuperar el ancho y el alto de la ventana para garantizar que los valores devueltos sean precisos.
Tkinter no ve si hay 2 o más monitores extendidos horizontal o verticalmente. Por lo tanto, obtendrá la resolución total de todas las pantallas juntas y su ventana terminará en algún lugar en el medio de las pantallas.
PyQt por otro lado, tampoco ve el entorno de varios monitores, pero obtendrá solo la resolución del monitor superior izquierdo (Imagine 4 monitores, 2 arriba y 2 abajo haciendo un cuadrado). Entonces, hace el trabajo al colocar la ventana en el centro de esa pantalla. Si no quieres usar ambos, PyQt y Tkintertal vez sería mejor ir con PyQt desde el principio.
El método más simple (pero posiblemente inexacto) es usar tk::PlaceWindow, que toma el nombre de ruta de una ventana de nivel superior como argumento. El nombre de ruta 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 conduce a una ligera desviación 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 quieres llamar al update_idletasks()
método
directamente antes de recuperar cualquier geometría, para garantizar que los valores devueltos sean precisos.
Hay 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)
Las dimensiones de la ventana y la ubicación se establecen con el método de geometría. La primera mitad de la geometría. string es el ancho y alto de la ventana Excluyendo el marco exterior,
y la segunda mitad son las coordenadas x e y de la parte superior izquierda del marco exterior.
win.geometry(f'widthxheight+x+y')
Ves la ventana moverse
Una forma de evitar que la ventana se mueva por la pantalla es utilizar
.attributes('-alpha', 0.0)
para hacer que la ventana sea completamente transparente y luego configúrela en 1.0
después de centrar la ventana. Utilizando withdraw()
o iconify()
más tarde seguido por deiconify()
no parece funcionar bien, para este propósito, en Windows 7. Yo uso deiconify()
como truco para activar la ventana.
Haciéndolo opcional
Es posible que desee considerar proporcionar al usuario una opción para centrar la ventana y no centrar 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 el movimiento de la ventana (como se indicó anteriormente).
Múltiples monitores
Si le preocupa el escenario de varios monitores, puede consultar el proyecto screeninfo o ver lo que puede lograr con Qt (PySide2) o GTK (PyGObject), y luego usar uno de esos kits de herramientas en lugar de tkinter. La combinación de kits de herramientas de GUI da como resultado una dependencia excesivamente grande.
Tk proporciona una función auxiliar que puede hacer esto como tk::PlaceWindow, pero no creo que se haya expuesto como un método envuelto en Tkinter. Centrarías un widget usando lo siguiente:
from tkinter import *
app = Tk()
app.eval('tk::PlaceWindow %s center' % app.winfo_pathname(app.winfo_id()))
app.mainloop()
Esta función también debería manejar varias pantallas correctamente. También tiene opciones para centrar sobre otro widget o relativo al puntero (usado para colocar menús emergentes), para que no se caigan de la pantalla.
Si haces scroll puedes encontrar los comentarios de otros desarrolladores, tú además tienes la libertad de insertar el tuyo si lo deseas.