python - funcion - Tkinter Grid: cómo colocar los widgets para que no se peguen
tkinter metodo grid (5)
Estoy intentando crear dos widgets de etiquetas que se encuentran en las esquinas superior izquierda y superior derecha de mi interfaz de usuario de prueba. El problema es que los widgets están pegados y me gustaría que hubiera espacio entre ellos.
En mi investigación, encontré sugerencias para usar las opciones sticky, padx y pady. Pero no importa qué argumentos le pase a .grid (), parece que no puedo crear espacio entre mis widgets. Entiendo que, independientemente del número de columnas y filas entre dos widgets, si dichas filas / columnas están vacías, es como si no existieran y los widgets aparezcan pegados.
Usando el método .grid (), ¿cómo puedo colocar los widgets para que no queden pegados?
Aquí está mi código hasta ahora:
#!/usr/bin/python
from Tkinter import *
class MyApp:
def __init__(self, parent):
self.myParent = parent
self.main_container = Frame(parent)
self.main_container.grid(row=0, rowspan=2, column=0, columnspan=4)
self.top_frame = Frame(self.main_container)
self.top_frame.grid(row=0, column=0, columnspan=4)
self.top_left = Frame(self.top_frame)
self.top_left.grid(row=0, column=0, columnspan=2)
self.top_right = Frame(self.top_frame)
self.top_right.grid(row=0, column=2, columnspan=2)
self.bottom_frame = Frame(self.main_container)
self.bottom_frame.grid(row=2, column=0, columnspan=4)
self.top_left_label = Label(self.top_left, text="Top Left")
self.top_left_label.grid(row=0, column=0, sticky=''W'', padx=2, pady=2)
self.top_right_label = Label(self.top_right, text="Top Right")
self.top_right_label.grid(row=0, column=4, sticky=''E'', padx=2, pady=2)
self.text_box = Text(self.bottom_frame, height=5, width=40)
self.text_box.grid(row=0, column=0)
root = Tk()
root.title("Test UI")
myapp = MyApp(root)
root.mainloop()
~ ~ Actualizar ~ ~
Intenté lo siguiente pero no funcionó:
self.top_left = Frame(self.top_frame)
self.top_left.grid(row=0, column=0, columnspan=2)
for c in range(2):
self.top_left.columnconfigure(c, weight=2)
self.top_right = Frame(self.top_frame)
self.top_right.grid(row=0, column=2, columnspan=2)
for c in range(2):
self.top_right.columnconfigure(c, weight=2)
Mejor tarde que nunca ;)
La "cuadrícula" de Tkinter quiere poner todo junto. Es por eso que no puedes saltarte las celdas. Tienes que especificar los anchos y luego anclar el texto. Añadí color para ayudar a mostrar las células. Pongo el bd en el marco. Luego tuve que dar ancho a las celdas izquierda y derecha para que la cuadrícula les diera peso. Luego ancla el texto al oeste o al este. No estoy seguro de por qué tuve que agregar 2 espacios adicionales para cada celda, pero pensé que era un problema de fuente.
Creo que Rodas es más limpio y sencillo, pero traté de mantenerme dentro de los parámetros sobre los que me pregunta.
El paquete es más fácil y más rápido para cosas pequeñas.
from tkinter import *
class MyApp:
def __init__(self, parent):
self.myParent = parent
self.main_container = Frame(parent, bg="green")
self.main_container.grid()
self.top_frame = Frame(self.main_container)
self.top_frame.grid()
self.top_left = Frame(self.top_frame, bd=2)
self.top_left.grid(row=0, column=0)
self.top_right = Frame(self.top_frame, bd=2)
self.top_right.grid(row=0, column=2)
self.top_left_label = Label(self.top_left, bd=2, bg="red", text="Top Left", width=22, anchor=W)
self.top_left_label.grid(row=0, column=0)
self.top_right_label = Label(self.top_right, bd=2, bg="blue", text="Top Right", width=22, anchor=E)
self.top_right_label.grid(row=0, column=0)
self.bottom_frame = Frame(self.main_container, bd=2)
self.bottom_frame.grid(row=2, column=0)
self.text_box = Text(self.bottom_frame, width=40, height=5)
self.text_box.grid(row=0, column=0)
root = Tk()
root.title("Test UI")
myapp = MyApp(root)
root.mainloop()
Aquí hay una manera fácil de hacerlo:
- Primero diseña tu interfaz gráfica de usuario en papel o con cualquier herramienta que funcione para ti
- Utilice el administrador de diseño de cuadrícula
- Donde quiera que desee crear un espacio vacío, utilice las propiedades de distribución de las columnas o de las filas de distribución, en combinación con la propiedad de las propiedades adhesivas, las columnas o las filas le permiten asignar más de una celda de la cuadrícula a un componente de la interfaz gráfica de usuario, y la propiedad de las propiedades adhesivas le permite forzar a ese elemento a seguir un lado (s) y deje un espacio vacío en el otro lado (s)
Si agrega bg = "red"
a los constructores top_left
y top_right
, verá cómo los Frames
se atascan en el centro, incluso utilizando la opción sticky
. Si no van a contener nada más que un solo widget, recomiendo no usarlos.
#!/usr/bin/python
from Tkinter import *
class MyApp:
def __init__(self, parent):
self.top_left_label = Label(parent, text="Top Left")
self.top_left_label.grid(row=0, column=0, padx=2, pady=2, sticky=N+S+W)
self.top_right_label = Label(parent, text="Top Right")
self.top_right_label.grid(row=0, column=1, padx=2, pady=2, sticky=N+S+E)
self.text_box = Text(parent, height=5, width=40)
self.text_box.grid(row=1, column=0, columnspan=2)
root = Tk()
root.title("Test UI")
myapp = MyApp(root)
root.mainloop()
Si necesita tener un control total sobre la colocación de su componente GUI, intente colocar el diseño; Un enfoque altamente manejable es organizar sus componentes en varios marcos, cada uno con una cuadrícula o diseño de paquete, y luego organizar todos esos marcos utilizando el diseño de lugar.
grid_columnconfigure
usar grid_columnconfigure
para dar un cierto peso a las columnas del medio. Con más peso que las otras columnas, se expandirán y contraerán para llenar cualquier espacio adicional que tenga. Sin embargo, en su caso, realmente no hay necesidad de utilizar la red. Todo en su GUI está alineado a lo largo de los lados particulares para los cuales el pack
es un ajuste más natural.
Mostraré cómo usar tanto el paquete como la cuadrícula, comenzando con el paquete ya que es lo más fácil. Incluso si insiste en usar grid
, lea la siguiente sección para comprender cómo dividir un problema de diseño grande en muchos problemas de diseño más pequeños.
Divide y conquistaras
La mejor manera de hacer el diseño en Tkinter es "dividir y conquistar". Comience con los widgets más externos y consígalos exactamente de la manera que desee. Luego, aborda cada uno de estos a la vez.
En su caso, tiene un widget más externo: el contenedor principal. Dado que es el único widget en la ventana, el paquete es la forma más sencilla de que llene todo el contenedor. También puede usar la cuadrícula, pero requiere un poco de trabajo adicional:
self.main_container = Frame(parent. background="bisque")
self.main_container.pack(side="top", fill="both", expand=True)
Ayuda a darle temporalmente colores distintivos a tus cuadros para que puedas visualizarlos a medida que los desarrolles. Agregue solo el código anterior a su __init__
, ejecute su aplicación, luego cambie el tamaño de la ventana para ver que el marco principal crece y se reduce correctamente.
A continuación, tiene dos marcos: top_frame y bottom_frame. Por sus nombres y a juzgar por cómo ha intentado usar la cuadrícula, asumo que deben completar la GUI en la dirección x. Además, supongo que el marco superior es una especie de barra de herramientas, y el marco inferior es la parte "principal" real de su GUI. Por lo tanto, vamos a hacer que el widget inferior ocupe todo el espacio extra.
Ya que estos se apilan uno encima del otro, el pack
es nuevamente la elección natural. Agregue el siguiente código, y solo el siguiente, para asegurarse de que estas áreas ocupen las partes de la ventana que espera y que tengan el comportamiento de cambio de tamaño adecuado.
self.top_frame = Frame(self.main_container, background="green")
self.bottom_frame = Frame(self.main_container, background="yellow")
self.top_frame.pack(side="top", fill="x", expand=False)
self.bottom_frame.pack(side="bottom", fill="both", expand=True)
A continuación vienen los marcos para las etiquetas. Una vez más, estos ocupan espacio a lo largo de los bordes de su contenedor, por lo que el pack
tiene más sentido. Y nuevamente, agregue solo el siguiente bit de código, ejecute su programa y asegúrese de que las cosas sigan cambiando de tamaño correctamente y llenando las partes correctas de la ventana:
self.top_left = Frame(self.top_frame, background="pink")
self.top_right = Frame(self.top_frame, background="blue")
self.top_left.pack(side="left", fill="x", expand=True)
self.top_right.pack(side="right", fill="x", expand=True)
A continuación, tienes tus etiquetas de "esquina". Nuevamente, dado que el contenedor es solo una fila de widgets, el pack
hace fácil. Ya que desea que las etiquetas estén en las esquinas, estableceremos el atributo sticky
un poco diferente para cada una:
self.top_left_label = Label(self.top_left, text="Top Left")
self.top_right_label = Label(self.top_right, text="Top Right")
self.top_left_label.pack(side="left")
self.top_right_label.pack(side="right")
Finalmente, tienes el widget de texto. Llena todo el marco inferior, así que una vez más, nuestro pack
es nuestro amigo:
self.text_box = Text(self.bottom_frame, height=5, width=40, background="gray")
self.text_box.pack(side="top", fill="both", expand=True)
paquete o rejilla?
Usaste cuadrícula para tu código original y preguntaste cómo arreglarlo. ¿Por qué usé el paquete para mis ejemplos?
Cuando utiliza el pack
, todas las opciones de configuración se pueden resumir en una sola llamada. Con la grid
junto con poner los widgets en sus contenedores, también debe tener cuidado de darle a sus columnas y filas "peso" para que se ajusten correctamente. Cuando simplemente apilas widgets uno sobre otro o los alineas en una fila, el pack
es mucho más fácil de usar.
En mis GUI, casi siempre uso una combinación de grid
y pack
. Ambos son poderosos, y sobresalen en cosas diferentes. Lo único que debe recordar, y esto es crucial , es que no puede usarlos en el mismo padre. Usando su código como ejemplo, no puede usar el pack
para el marco top_left y la grid
para el marco top_right, ya que ambos comparten el mismo padre. Sin embargo, puedes mezclarlos dentro de la misma aplicación.
Una vez más, utilizando rejilla.
Ok, entonces tal vez realmente quieras usar la grid
: tal vez esta sea una tarea escolar, o tal vez solo quieras enfocarte en un administrador de geometría a la vez. Eso es genial. Así es como lo haría. De nuevo, debes dividir y conquistar:
Comience con el marco principal. Reemplace la instrucción donde empaquetamos el contenedor principal con las siguientes líneas. Observe que tenemos que configurar las filas y columnas en el padre , no el marco que creamos.
self.main_container.grid(row=0, column=0, sticky="nsew")
self.myParent.grid_rowconfigure(0, weight=1)
self.myParent.grid_columnconfigure(0, weight=1)
Ok, ahora para los marcos superior e inferior. Retire el pack
, y agregue las siguientes líneas. Todavía tienes una sola columna, pero esta vez hay un par de filas. Fíjate qué fila tiene un peso de 1:
self.top_frame.grid(row=0, column=0, sticky="ew")
self.bottom_frame.grid(row=1, column=0,sticky="nsew")
self.main_container.grid_rowconfigure(1, weight=1)
self.main_container.grid_columnconfigure(0, weight=1)
Los marcos de las esquinas - ¡por fin, un contenedor con más de una columna! Vamos a crear una tercera columna en el medio para ocupar todo el margen. Reemplace las declaraciones del pack
con lo siguiente, prestando mucha atención a lo que se le da "peso":
self.top_left.grid(row=0, column=0, sticky="w")
self.top_right.grid(row=0, column=2, sticky="e")
self.top_frame.grid_columnconfigure(1, weight=1)
A continuación, las etiquetas en sus marcos. Como no los necesitamos para expandir, podemos mantener el peso predeterminado de cero. Puede parecer extraño que ambas etiquetas estén en la columna cero. Recuerda que están en padres diferentes, y son los únicos widgets de sus padres, por lo que solo hay una columna en cada uno:
self.top_left_label.grid(row=0, column=0, sticky="w")
self.top_right_label.grid(row=0, column=0, sticky="e")
Finalmente tenemos el widget de texto que es el único widget en el marco inferior. Reemplace las declaraciones del pack
final con lo siguiente:
self.text_box.grid(row=0, column=0, sticky="nsew")
self.bottom_frame.grid_rowconfigure(0, weight=1)
self.bottom_frame.grid_columnconfigure(0, weight=1)
Conclusión
Diseñar widgets es fácil, pero tienes que ser sistemático al respecto. Piense en lo que está haciendo, organice sus widgets en grupos y luego aborde los grupos uno por uno. Cuando haga eso, debería ser evidente qué administrador de geometría debería usar.
Como puede ver, la grid
requiere algunas líneas más de código, pero es la elección correcta cuando realmente tiene una cuadrícula. En su caso, ya había subdividido su GUI en secciones, y aunque el resultado final fue una cuadrícula, cada sección se empaquetó en la parte superior o inferior de otra, o en los bordes izquierdo o derecho. En estos casos, el pack
es un poco más fácil de usar, ya que no tiene que preocuparse por los pesos de fila y columna.