python - ubicar - toplevel tkinter
¿Cómo centrar una ventana en la pantalla en Tkinter? (7)
Estoy tratando de centrar una ventana de tkinter. Sé que puedo obtener programáticamente el tamaño de la ventana y el tamaño de la pantalla y usar eso para establecer la geometría, pero me pregunto si hay una forma más simple de centrar la ventana en la pantalla.
Esta respuesta es mejor para entender 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()
El enfoque general para centrar una ventana es calcular las coordenadas de pantalla apropiadas para el píxel superior izquierdo de la ventana:
x = (screen_width / 2) - (window_width / 2)
y = (screen_height / 2) - (window_height / 2)
Sin embargo, esto no es suficiente para centrar con precisión una ventana de tkinter (en Windows 7 al menos);
porque el ancho y el alto de la ventana devueltos por cualquier método no incluirán el marco más externo, con el título y los botones min / max / close. Tampoco incluirá una barra de menú (con Archivo, Edición, etc.). Afortunadamente, hay una manera de encontrar las dimensiones de estos.
Aquí está la función más básica, que no tiene en cuenta el problema antes mencionado:
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))
Alternativas: winfo_reqwidth()
, winfo_reqheight()
En primer lugar, y ante todo, queremos llamar al método update_idletasks()
la ventana
directamente antes de recuperar cualquier geometría, para garantizar que los valores devueltos sean precisos.
Es importante comprender las cadenas de geometría utilizadas con el método geometry()
.
La primera mitad es el ancho y alto de la ventana excluyendo el marco exterior,
y la segunda mitad es la parte superior izquierda del cuadro exterior xey coordenadas.
Hay cuatro métodos que nos permitirán determinar las dimensiones del marco exterior.
winfo_rootx()
nos dará la coordenada x superior izquierda de la ventana, excluyendo el marco externo.
winfo_x()
nos dará la coordenada x superior izquierda del marco externo.
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)
Aquí está la función completa, en un ejemplo de trabajo:
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()
Una forma de evitar que la ventana se mueva por la pantalla es usar .attributes(''-alpha'', 0.0)
para que la ventana sea completamente transparente y luego establecerla en 1.0
después de que la ventana se haya centrado. El uso de withdraw()
o iconify()
más tarde seguido de deiconify()
no parece funcionar bien, para este propósito, en Windows 7. Tenga en cuenta que utilizo deiconify()
como un truco para activar la ventana.
He encontrado una solución para la misma pregunta en este sitio
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()
seguro, lo cambié correspondientemente a mis propósitos, funciona.
Tk proporciona una función auxiliar que puede hacer esto como tk::PlaceWindow
, pero no creo que haya sido expuesto como un método envuelto en Tkinter. Deberías centrar 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 debe tratar múltiples pantallas correctamente. También tiene opciones para centrar sobre otro widget o relativo al puntero (utilizado para colocar menús emergentes), para que no se salgan de la pantalla.
Utilizar:
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()
Yo uso la opción de marco y expandir. Muy simple. Quiero algunos botones en el medio de la pantalla. Cambiar el tamaño de la ventana y el botón permanecer en el medio. Esta es mi solución.
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)
Puede intentar utilizar los métodos winfo_screenwidth
y winfo_screenheight
, que devuelven respectivamente el ancho y el alto (en píxeles) de su instancia Tk
(ventana), y con algunos cálculos básicos 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
método 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 horizontales o verticales. 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 múltiples monitores, pero obtendrá solo la resolución del monitor de la parte superior izquierda (Imagine 4 monitores, 2 arriba y 2 abajo haciendo un cuadrado). Por lo tanto, hace el trabajo al poner la ventana en el centro de esa pantalla. Si no desea utilizar ambos, PyQt y Tkinter , tal vez sería mejor ir con PyQt desde el inicio.