tkinter Grid

El método grid nos permite posicionar los widgets en una celda en especifico, indicamos la celda usando el índice de fila y columna correspondiente, el ancho y la altura de cada celda son configurables, además un widget puede ocupar varias celdas si lo deseamos, usando grid podemos crear fácilmente interfaces gráficas de usuario tipo formulario.

Un ejemplo simple, para posicionar el widget w usando el método grid() deberemos indicar como mínimo la fila y la columna donde este se ubicará, de este modo: w.grid(row=1, column=2) en este ejemplo el widget w se ubicará en la celda correspondiente a la fila 1 y la columna 2, los índices de filas y columnas inician de cero.

En este otro ejemplo creamos una matriz de elementos Entry (cuadro que nos permite escribir texto), a cada uno le asignamos el valor de fila y columna que le corresponde.

tkinter grid

El código Python tkinter es el siguiente:

from tkinter import *

root = Tk()

for r in range(0, 5):
    for c in range(0, 5):
        cell = Entry(root, width=10)
        cell.grid(row=r, column=c)
        cell.insert(0, '({}, {})'.format(r, c))

root.mainloop()

Bastante simple, pero nos sirve para comprender como se organizan los widgets con grid().

Si deseamos crear un espacio entre las filas o columnas podemos usar pady y padx en cada uno de ellos indicamos la cantidad de espacio deseada, ejemplo.

from tkinter import *

root = Tk()

for r in range(0, 5):
    for c in range(0, 5):
        cell = Entry(root, width=10)
        cell.grid(padx=5, pady=5, row=r, column=c)
        cell.insert(0, '({}, {})'.format(r, c))

root.mainloop()

tkinter espacio entre celdas de grid

También disponemos de ipadx e ipady que funcionan de manera similar, salvo que el espacio es a lo interno de la celda, prueba y compara los resultados para entender mejor.

Para crear una GUI tipo formulario solo añadimos los widget en las celdas correspondientes, para el ejemplo que se muestra en la imagen, tenemos 3 filas y 2 columnas, si le prestamos atención al botón veremos que ocupa dos columnas.

tkinter formulario con grid

from tkinter import *

root = Tk()

Label(root, text="Nombre:").grid(pady=5, row=0, column=0)
Label(root, text="Apellido:").grid( pady=5, row=1, column=0)

Entry(root, width=40).grid(padx=5, row=0, column=1)
Entry(root, width=40).grid(padx=5, row=1, column=1)

Button(root, text="Aceptar", width=50).grid(padx=10, pady=10, row=2, column=0, columnspan=2)

root.mainloop()

Para que el botón se posicione en dos columnas usamos columnspan=2 podemos indicar la cantidad de columnas que sean necesarias, del mismo modo si deseamos que un widget se posicione en más de una fila usaremos rowspan= indicando la cantidad de filas.

En este código de ejemplo tenemos un problema, al cambiar el tamaño de la ventana los widget mantienen su tamaño, si deseamos que los mismo se expandan con la ventana, como se muestra en la imagen debemos hacer lo siguiente.

tkinter grid expandible

from tkinter import *

root = Tk()

root.columnconfigure(0, weight=0)
root.columnconfigure(1, weight=1)
root.rowconfigure(2, weight=1)

Label(root, text="Nombre:").grid(row=0, column=0)
Label(root, text="Apellido:").grid(row=1, column=0)

Entry(root).grid(row=0, column=1, sticky=E+W)
Entry(root).grid(row=1, column=1, sticky=E+W)

Button(root, text="Aceptar").grid(pady=10,
                                  padx=10,
                                  row=2,
                                  column=0,
                                  columnspan=2,
                                  sticky=S+N+E+W)

root.mainloop()

A los widget que deseamos hacer expandible le agregamos sticky= para indicar a que posición se ancla en mismo, para los Entry usamos sticky=E+W indicando que los mismos están anclados a la derecha y a la izquierda de la celda, puedes ver la imagen con las distintas posiciones de anclaje.

tkinter anchor

Con en widget Button usamos sticky=S+N+E+W de este modo decimos que está anclado a las 4 posiciones respectivas.

Para finalizar debemos configurar la fila o columna para que se expanda, lo hacemos con root.columnconfigure(1, weight=1), donde el primer parámetro se refiere a la columna deseada y el segundo lo establecemos a 1 a obtener el comportamiento deseado, podemos hacer lo mismo con una fila usando rowconfigure .

Comentarios

  1. Buenas, después de crear la matriz, como puedo acceder a los datos ingresados en cada uno de los "Entry"?? Hay qie crear una variable para cada uno de ellos??
    Gracias
    P.D.: soy novato!!

    ResponderEliminar
    Respuestas
    1. Efectivamente, se necesita crear tantas variables como widget tipo Entry dispongas. En tal caso las variables se definen como StringVar(). Por ejemplo:

      Nombre=StringVar()

      Dentro de la definición del Entry correspondiente debes especificar que se relaciona con esa variable creada, por ejemplo, suponiendo que tu cajita de texto se llame "CajaNom":

      CajaNom=Entry(Frame1, textvariable=Nombre)

      De esta manera todo lo ingresado en CajaNom, se vuelca temporalmente en la variable Nombre, la cual podrás manipular luego desde el código de la siguiente manera:

      NombreObtenido=Nombre.get()

      De manera contraria, para insertar un valor desde el código a tu cajita de texto se hace mediante esa misma variable pero con el método .set(), por ejemplo:

      Nombre.set("Abigaíl")

      Entonces en tu caja de texto llamada CajaNom, aparecerá el texto "Abigaíl".

      Espero te sirvan estos ejemplos.
      Saludos!

      Eliminar
  2. Con un bucle while y otro for consigo hacer una matriz de las celdas que desee, el problema radica cuando quiero acceder a la información que contiene la celda.
    He conseguido, manualmente, en una matriz de cuatro celdas guardar info y poder recuperarla....el problema sería si necesito una matriz, por ejemplo de 50 celdas......aquí le dejo parte del código:

    x = 2 #número de filas que queremos
    y = -1 #indicador de files

    posiciones = []

    casilla00 = StringVar()
    casilla01 = StringVar()
    casilla10 = StringVar()
    casilla11 = StringVar()


    while x > 0:
    y = y + 1
    x = x - 1

    for i in range(2): #el "range" nos indica las columnas

    ###NO SE PUEDE EMPAQUETAR???
    if y==0 and i==0:
    casi00 = Entry(root, width=10, textvariable=casilla00)
    casi00.grid(row=y, column=i)
    elif y==0 and i==1:
    casi01 = Entry(root, width=10, textvariable=casilla01)
    casi01.grid(row=y, column=i)
    elif y==1 and i==0:
    casi10 = Entry(root, width=10, textvariable=casilla10)
    casi10.grid(row=y, column=i)
    else:
    casi11 = Entry(root, width=10, textvariable=casilla11)
    casi11.grid(row=y, column=i)

    posiciones.append((y,i))
    print(posiciones)


    casilla00.set(posiciones[0])
    casilla01.set(posiciones[1])
    casilla10.set(posiciones[2])
    casilla11.set(posiciones[3])

    Saludos!

    ResponderEliminar
  3. Nota: al "copiar" y "pegar" se han perdido las identaciones.

    ResponderEliminar
  4. cuando un usuario rellena o modifica el contenido de las celdas, como se puede recuperar lo que ha entrado el usuario?, alguna idea, codigo, ... ?

    ResponderEliminar
  5. # llegué tarde?... se me ocurre algo así...espero sirva de algo...
    from tkinter import * # Carga módulo tk (widgets estándar)

    def imprime():
    ....for r in range(0,5):
    ........for c in range(0,5):
    ........strCelda='Celda' + str(r) + str(c) + '.get()' # 'Celda00.get()'
    ............print(eval(strCelda))

    root = Tk()

    for r in range(0,5):
    ....for c in range(0,5):
    ........strCelda='Celda' + str(r) + str(c)
    ........sv = strCelda + '=StringVar()' # "Celda00=StringVar()"
    ........codigo = compile(sv, "Dummy", 'exec')
    ........ejecutar = exec(codigo) # Crea (ejecuta) la variable Celda00...

    ........cell = Entry(root, width=10, textvariable=eval(strCelda)) # eval(strCelda) es Celda00
    ........cell.grid(row=r, column=c)
    ........cell.insert(0, '({}, {})'.format(r, c))

    ........#cell.insert(0,strCelda)
    boton = Button(root, text="print Celdas", command=imprime).grid(row=5, column=0)

    root.mainloop()

    ResponderEliminar
  6. # grid de Botones dinámicos llamando una función dinámica que llama a una función general
    from tkinter import * # Carga módulo tk (widgets estándar)

    def BotonGral(strBoton):
    ....print("Desde la función BotonGral")
    ….print("El botón presionado es", strBoton)

    root = Tk()

    for r in range(0,5):
    ....for c in range(0,5):
    ........strCelda='Boton' + str(r) + str(c)
    ........funcion = "def " + strCelda + "():print('" + strCelda + "')" #funcion Boton00() que imprime strCelda
    ........funcion = "def " + strCelda + "():BotonGral('" + strCelda + "')" #funcion BotonGral(strCelda)
    ........codigo = compile(funcion, "Dummy", 'exec')
    ........ejecutar = exec(codigo)

    ........sv = strCelda + "=Button(root, width=30, text='funcion " + strCelda+"', command=" + strCelda + ").grid(row="+ str(r) +", column=" + str(c) + ")"
    ........codigo = compile(sv, "Dummy", 'exec')
    ........ejecutar = exec(codigo)

    root.mainloop()

    ResponderEliminar
  7. Se puede hacer que el texto del botón("Aceptar") también cambie de tamaño dependiendo del tamaño del botón o ese no se puede modificar?

    ResponderEliminar
  8. GRACIAS ! muy buena la explicacion para los que recien empezamos a aprender python ( actualmente programo en visual fox pro ) . queria consultar como se puede usar un grid para mostrar el contenido de una tabla de mysql por ejemplo de tres campos , legajo , nombre , apellido . gracias

    ResponderEliminar
  9. str = "cell{}{}".format(r, c)
    print(str)
    locals()[str] = Entry(root, width=10) # cell00
    locals()[str].grid(padx=5, pady=5, row=r, column=c)

    esto va dentro del bucle, ahora ya tienes cada celda con nombre y variable propia, nadamas accedes con ej cell00.get(), yo lo estoy haciendo a travez de un button y un extend en una lista bidimencional y ahora pudes acceder presionando el botton sin desaser el bucle !!!

    ResponderEliminar

Publicar un comentario

Temas relacionados

Entradas populares de este blog

tkinter Canvas

Histogramas OpenCV Python

Conectar SQL Server con Java

JavaFX Uso de ComboBox