Tkinter Tutorial - Gestión de la disposición

Jinku Hu 30 enero 2023
  1. Método de disposición de Tkinter pack
  2. Método de diseño grid de Tkinter
  3. Método place de Tkinter
Tkinter Tutorial - Gestión de la disposición

En las secciones anteriores, hemos introducido varios tipos de widgets de Tkinter, como label, button, menú desplegable, etc. Mientras tanto, también hemos mencionado brevemente cómo diseñar estos widgets en la ventana del programa. Este es el punto clave que aprenderá en esta sección - los métodos de gestión de la geometría de Tkinter.

Tkinter tiene tres métodos de gestión de la geometría, es decir, pack, grid, y place. Vamos a repasarlos uno por uno.

Método de disposición de Tkinter pack

El método pack, como se indica literalmente, empaqueta el widget en el marco de la ventana después de ser creado. Nos encontramos con este método de empaquetado en la sección Tkinter Label donde también se listan todas las opciones de pack.

Le mostraremos cómo diseñar widgets con el método pack (también sus opciones). Unos pocos ejemplos ayudan a demostrar la configuración correcta.

Disposición de Tkinter pack - Posición relativa

import tkinter as tk

app = tk.Tk()
app.geometry("300x200")

buttonW = tk.Button(app, text="West", width=15)
buttonW.pack(side="left")

buttonE = tk.Button(app, text="East", width=15)
buttonE.pack(side="right")

app.mainloop()

Ejecute el programa, obtendrá una ventana como esta,

Posición relativa del lado del método de disposición de los paquetes Tkinter

Como puedes ver, buttonWest se ajusta al lado izquierdo de la ventana y buttonEast se ajusta al lado derecho de la ventana. Puede intentar escalar el tamaño de la ventana más abajo, pero verá que aún se aferran a los lados de la ventana y la posición relativa no cambiará.

buttonW.pack(side="left")

El lado tiene cuatro opciones -

  1. top
  2. bottom
  3. left
  4. right

Coloca el widget en el side de la ventana. Como se ilustra en el ejemplo, buttonW se asigna en el lado izquierdo de la ventana, porque side='left', mientras que buttonE está en el lado derecho de la ventana, porque side='right'.

Ahora tenemos un escenario interesante, ¿qué pasa si dos widgets tienen la misma propiedad side, cómo será el diseño?

Intenta responder tú mismo, o compruébalo ejecutando los siguientes códigos.

import tkinter as tk


app = tk.Tk()
app.geometry("300x200")

buttonW = tk.Button(app, text="West", width=15)
buttonW.pack(side="left")

buttonE1 = tk.Button(app, text="East 1", width=15)
buttonE1.pack(side="right")

buttonE2 = tk.Button(app, text="East 2", width=15)
buttonE2.pack(side="right")

app.mainloop()

Tkinter pack para añadir el relleno interno y externo del widget

En algunos casos, necesitas añadir algún relleno dentro o fuera del widget para que haya menos congestión entre los widgets, y también entre el texto del widget y los límites del mismo. Ahora, necesitas opciones como padx, pady, ipadx y ipadx.

import tkinter as tk

app = tk.Tk()
app.geometry("300x200")

buttonW = tk.Button(app, text="West")
buttonW.pack(side="left", ipadx=20, padx=30)

buttonE = tk.Button(app, text="East")
buttonE.pack(side="right", ipadx=20, padx=30)

app.mainloop()

Método de diseño de paquetes de Tkinter - incrementa el relleno de los widgets

Ambos botones añaden el relleno interior de 20 unidades y el exterior de 30 unidades en la x, y la unidad es el píxel pero no el ancho de un carácter.

Tkinter pack Layout Relleno en dirección x, y

La siguiente implementación de código podría llenar automáticamente la dimensión del widget al mismo ancho o alto que la ventana, y cuando se hace un zoom en la ventana, el tamaño del control puede cambiar automáticamente con el tamaño de la ventana.

import tkinter as tk

app = tk.Tk()
app.geometry("300x200")

buttonX = tk.Button(app, text="Fill X", bg="red", height=5)
buttonX.pack(fill="x")

buttonY = tk.Button(app, text="Fill Y", bg="green", width=10)
buttonY.pack(side="left", fill="y")

app.mainloop()

Tkinter pack Método de disposición Relleno en dirección X,Y

butonX.pack(fill='x') significa que buttonX llenará el ancho de toda la ventana. De forma similar, fill='y' llenará la altura de toda la ventana, y mientras tanto fill='both' llenará tanto el ancho como la altura.

Tkinter pack Opción de diseño expand - expandir automáticamente

La opción fill= de arriba rellenará automáticamente el widget en dirección x y/o y cuando se modifique el tamaño de la ventana. Otro requisito similar es cómo mostrar automáticamente todo el contenido si el widget incluye múltiples opciones, como una lista?

import tkinter as tk
import calendar

app = tk.Tk()

buttonX = tk.Button(app, text="Label ", bg="blue", height=5)
buttonX.pack(fill="x")

listboxA = tk.Listbox(app, width=10)
listboxA.pack(fill="both", expand=1)

for i in range(1, 13):
    listboxA.insert(tk.END, calendar.month_name[i])

app.mainloop()

El método de diseño de paquetes de Tkinter habilita la opción de expansión

Cuando expand=True o expand=1, la lista desplegará todos los elementos, desde January a December como se muestra en el ejemplo anterior.

Si expand está configurado como False, entonces la lista sólo muestra los primeros 10 elementos por defecto. Necesita usar el ratón o las teclas de dirección para mostrar los elementos ocultos después de que la lista de elementos sea seleccionada.

listboxA.pack(fill="both", expand=0)

expand=0 deshabilita la lista para mostrar automáticamente todos los elementos.

El método de diseño de paquetes de Tkinter cuando la opción expandir está deshabilitada

Método de diseño grid de Tkinter

Tkinter grid es otro y también el más importante método de geometría de diseño. Este es el que debería aprender si sólo quiere aprender un único método entre todos los gestores de geometría.

La grid se usa a menudo en los cuadros de diálogo, y podría colocar los widgets basados en las coordenadas de posición de la cuadrícula. El método de diseño grid podría tener posiciones relativas estables de todos los widgets.

El siguiente ejemplo creará una interfaz gráfica relativamente complicada comparada con los ejemplos anteriores, que usa tantas opciones de grid como sea posible y que se explicarán en las siguientes secciones.

import tkinter as tk

app = tk.Tk()

labelWidth = tk.Label(app, text="Width Ratio")
labelWidth.grid(column=0, row=0, ipadx=5, pady=5, sticky=tk.W + tk.N)

labelHeight = tk.Label(app, text="Height Ratio")
labelHeight.grid(column=0, row=1, ipadx=5, pady=5, sticky=tk.W + tk.S)


entryWidth = tk.Entry(app, width=20)
entryHeight = tk.Entry(app, width=20)

entryWidth.grid(column=1, row=0, padx=10, pady=5, sticky=tk.N)
entryHeight.grid(column=1, row=1, padx=10, pady=5, sticky=tk.S)


resultButton = tk.Button(app, text="Get Result")
resultButton.grid(column=0, row=2, pady=10, sticky=tk.W)

logo = tk.PhotoImage(file="python.gif")
labelLogo = tk.Label(app, image=logo)

labelLogo.grid(
    row=0,
    column=2,
    columnspan=2,
    rowspan=2,
    sticky=tk.W + tk.E + tk.N + tk.S,
    padx=5,
    pady=5,
)

app.mainloop()

Método de diseño de la parrilla de Tkinter

Opciones de grid, column y row de Tkinter

labelWidth.grid(column=0, row=0, ipadx=5, pady=5, sticky=tk.W + tk.N)

Cada widget será colocado en la celda absoluta en el método de diseño grid. La coordenada de la celda se determina por column y row.

El widget labelWidth se coloca en la celda de la posición (0, 0). La coordenada comienza en la esquina superior izquierda de la ventana.

Las opciones ipadx, ipady, padx y pady son las mismas que las del método pack.

Opción grid sticky de Tkinter

sticky determina cómo se pega el widget a la celda cuando el widget es más pequeño que la celda.

sticky Significado
W pegarse a la izquierda
E mantenerse a la derecha
N pegarse a la parte superior
S adherirse al fondo

La opción sticky por defecto es el centro, es decir, W+E+N+S.

Opciones columnspan y rowspan de Tkinter

labelLogo.grid(
    row=0,
    column=2,
    columnspan=2,
    rowspan=2,
    sticky=tk.W + tk.E + tk.N + tk.S,
    padx=5,
    pady=5,
)

La coordenada de la celda de labelLogo es (column=2, row=0) y el tamaño del logo es relativamente grande, por lo que se asigna un tamaño de celda de 2x2. arrowspan = 2 y rowspan=2 significan que el widget tiene tramos de dos celdas en las direcciones X y Y empezando desde la posición del widget.

Método place de Tkinter

El método place de Tkinter coloca el widget en una posición absoluta o relativa en la ventana. Seguimos usando el mismo enfoque de arriba para introducir las opciones de este método de diseño.

import tkinter as tk

app = tk.Tk()
app.geometry("300x300")

labelA = tk.Label(app, text="Label (0, 0)", fg="blue", bg="#FF0")
labelB = tk.Label(app, text="Label (20, 20)", fg="green", bg="#300")
labelC = tk.Label(app, text="Label (40, 50)", fg="black", bg="#f03")
labelD = tk.Label(app, text="Label (0.5, 0.5)", fg="orange", bg="#0ff")

labelA.place(x=0, y=0)
labelB.place(x=20, y=20)
labelC.place(x=40, y=50)
labelD.place(relx=0.5, rely=0.5)

app.mainloop()

Método Tkinter place Layout

Tkinter place Posición absoluta

labelA.place(x=0, y=0)
labelB.place(x=20, y=20)

Las opciones x= y y= en place determinan las posiciones absolutas del widget, que tienen la unidad como pixel. Por ejemplo, lableB.place(x=20, y=20) significa que labelB se coloca en la coordenada de (20, 20).

Posición relativa de Tkinter place

El inconveniente de la posición absoluta es que si hay otros widgets en la ventana colocados con posiciones relativas, cuando la ventana se amplía, el widget que usa la disposición de posición absoluta posiblemente tendrá la superposición con otros widgets.

El método de diseño place también tiene la opción de posición relativa, es decir,

labelD.place(relx=0.5, rely=0.5)

Donde relx y rely están en el rango de 0.0~1.0. Es el porcentaje relativo de la posición del widget con respecto al tamaño de la ventana.

Por ejemplo, relx=0.5, reli=0.5 significa que el widget se coloca en el 50% de la anchura y el 50% de la altura de la ventana.

relx=1.0 es el límite derecho de la ventana, y rely=1.0 es el límite inferior de la ventana.

Autor: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.

LinkedIn Facebook