Interfaces gráficas

¿Qué es una interfaz gráfica?

Básicamente una interfaz gráfica  es el conjunto de elementos visuales que nos permiten interactuar con un programa. Por sus siglas en inglés se puede encontrar como GUI (Graphic User Interface). Para crear interfaces gráficas en Python es necesario trabajar con librerías externas, en nuestro caso vamos a usar la librería TKINTER, que funciona básicame como puente entre Python y la librería gráfica TCL/TK, pero no es la única que existe, podemos encontrar tambien WXPYTHON, PYQT y PYGTK. Por defecto TKINTER viene ya preinstalado con Python en Windows y Linux. En Python una interfaz gráfica se puede componer de una raíz, un frame contenido dentro de la raíz, y un conjunto de widgets o componentes contenidos dentro del frame, los widges mas comunes son botones de texto, cuadros de texto, imágenes, cuadros combinados de selección, etc. Hay que tomar en cuenta que el frame es considerado también como un widget.

Nota: La documentación completa de la librería TKInter se puede encontrar en https://docs.python.org/es/3/library/tkinter.html#

Raíz

Para crear la raíz basta con importar la librería Tkinter, instanciar en un objeto la clase TK() y posteriormente ejecutar el método MAINLOOP(). Veamos el siguiente ejemplo:


from tkinter import *

raiz=Tk()
 
raiz.mainloop()


Resultado:

Como podemos ver se ha creado una ventana estandar de Windows o lo que es lo mismo en Python una raíz. Esta ventana queda en un loop infinito hasta que el usuario la cierre en el botón cerrar "X", como cualquier ventana de Windows. El método MAINLOOP() ejecuta la ventana raíz y se encuentra a la escucha continua de los eventos que puedan ocurrir mientras se ejecuta para responder apropiadamente ante ellos.

Si bien esta es una ventana genérica sin mayor atractivo, podemos empezar a personalizarla, por ejemplo dándole un título. Esto se logra a través del método .TITLE(). Veamos el ejemplo práctico:

from tkinter import *

raiz=Tk()
raiz.title('Ventana de pruebas en Python')
raiz.mainloop()

Resultado:



Ahora ha cambiado el título de la ventana y se muestra el que le hemos especificado. Es importante que la instrucción mainloop() este de último.

También es posible boquear la posibilidad de redimensionar la ventana mostrada. Para ello basta con establecer los valores booleanos en el método .RESIZABLE(), siendo 0 y 0 ó FALSE Y FALSE respectivamente para los valores width y height (ancho y alto) para que se bloquee el ancho y alto de la ventana imposibilitando su redimensionamiento. Veamos como quedaria en la práctica:
  
from tkinter import *

raiz=Tk()
raiz.title('Ventana de pruebas en Python')
raiz.resizable(0,0)

raiz.mainloop()

Resultado:

En este caso Python no permite el redimensionamiento de la ventana ya que ha sido bloqueada esta posibilidad con el método .RESIZABLE. De hecho se ha deshabilitado el botón de maximizar y restaurar y al pasar el ratón por encima del borde ya no aparece la flecha de redimensionamiento de ventana. Tambien es posible activar o desactivar el redimensionado independientemente uno del otro, por ejempo activar el redimensionado a lo ancho pero no a lo alto y viceversa. Veamos el siguiente ejemplo:

from tkinter import *

raiz=Tk()
raiz.title('Ventana de pruebas en Python')
raiz.resizable(True,0)

raiz.mainloop()

Resultado:


Otro ejemplo cambiando la posibilidad de redimensionamiento de las coordenadas:


En este segundo ejemplo hemos bloqueado la posibilidad de redimensionamiento a lo ancho pero hemos permitido el redimensonamiento a lo alto. Nótese el uso indiferente de los valores booleanos TRUE, FALSE,  0 y 1.

A pesar de no verse en las imágenes, las ventanas aquí expuestas e intentaron redimensionar en ambas direcciones para comprobar el funcionamiento de bloqueo y desbloqueo del redimensionamiento de ambas dimensiones ancho y alto, con el resultado obtenido mostrado en pantalla.

Otra posibilidad de personalización de la ventana principal es el cambio del ícono en la parte superior izquierda. Esto se logra a través del método .ICONBITMAP(), veamos un ejemplo:

from tkinter import *

raiz=Tk()
raiz.title('Modificación de ícono por defecto')
raiz.resizable(1,1)
raiz.iconbitmap('python_icon.ico')

raiz.mainloop()

Resultado:



Obviamente hay que tener previamente el archivo del ícono en el directorio del script para poder cargarlo.

Es posible estalecer el tamaño al que se va a mostar la ventana principal, esto a través del método .GEOMETRY(), veamos el siguiente ejemplo:

from tkinter import *

raiz=Tk()
raiz.title('Estableciendo tamaño de ventana por defecto')
raiz.resizable(0,0)
raiz.iconbitmap('python_icon.ico')
raiz.geometry('640x480')

raiz.mainloop()

Resultado:



Como podemos ver el tamaño de la ventana ahora es de 640 pixeles de ancho por 480 pixeles de alto y ha salido así por defecto, no ha sido necesario ningun redimensionamiento.

Orta opción que podemos modificar muy facilmente es el color de fondo de la ventana. Esto se logra a través de método .CONFIG() con la opción 'BG=<color de fondo deseado>', veamos el siguiente ejemplo:

from tkinter import *

raiz=Tk()
raiz.title('Estableciendo color de fondo a azul oscuro')
raiz.resizable(0,0)
raiz.iconbitmap('python_icon.ico')
raiz.geometry('640x480')
raiz.config(bg='dark blue')

raiz.mainloop()

Resultado:


Es posible definir los colores por su código hexadecimal. Supongamos que deseamos cambiar el color de fondo de la ventana a '#A9CCE3 ', el código quedaría de la siguiente manera:

from tkinter import *

raiz=Tk()
raiz.title('Estableciendo color de fondo a #A9CCE3')
raiz.resizable(0,0)
raiz.iconbitmap('python_icon.ico')
raiz.geometry('640x480')
raiz.config(bg='#A9CCE3')

raiz.mainloop()

Resultado:


El script en el que esta escrito el código de la interfaz gráfica esta guardado en un archivo .py, al igual que los ejempos anteriores en las otras secciones, esto hace que Python abra la cónsola del sistema operativo de fondo mientas ejecuctala interfaz gráfica. Para evitar esto y hacer que no aparezca la cónsola del sistema operativo, basta con cambiar la extensión del archivo de .py a .pyw, o sea Python para Windows.

Frames

Los frames son un tipo de widget o de componente visual cuya función específica es la de servir de contenedor de otros widgets. Se pueden considerar visualmente como cuadros configurables que agrupan otros widgets. Veamos un ejemplo de su declaración:

from tkinter import *

raiz=Tk()
raiz.title('Creando frames')
#raiz.resizable(0,0)
raiz.iconbitmap('python_icon.ico')
#raiz.geometry('800x600')
raiz.config(bg='dark gray')
frame_raiz=Frame()

raiz.mainloop()

Resultado:


Como podemos ver aparentemente no hay ningun cambio con lo que hemos enido haciendo hasta ahora con la ventana principal, o sea el objeto raiz, a la cual por cierto le hemos asignado un color gris oscuro. Esto ocurre por que es necesario empaquetarlo, llo que significa meter el frame en la raíz, a través del método pack:

from tkinter import *

raiz=Tk()
raiz.title('Creando frames')
#raiz.resizable(0,0)
raiz.iconbitmap('python_icon.ico')
#raiz.geometry('800x600')
raiz.config(bg='dark gray')
frame_raiz=Frame()
frame_raiz.pack()

raiz.mainloop()

Si se ejecuta el código en este punto obtendremos:


Esto es una ventana con el frame empaquetado pero posee tamaño 0,0 ya que no se ha definido aún en las propiedades de configuración del frame. Es importante destacar que las propiedades de configuración del objeto frame aplican igual que las propiedades de configuración del objeto raiz.

from tkinter import *

raiz=Tk()
raiz.title('Creando frames')
#raiz.resizable(0,0)
raiz.iconbitmap('python_icon.ico')
#raiz.geometry('800x600')
raiz.config(bg='dark gray')
frame_raiz=Frame()
frame_raiz.config(width=800,height=600)
frame_raiz.pack()

raiz.mainloop()


Resultado:


Ahora el frame tiene un tamaño de 800 x 600 px obligando a la raiz a expandirse a esas mismas medidas.

La personalización del frame va mas allá, podemos al igual que cno la ventana raíz, cambiar el color de fondo, siendo distinguible del color de fondo de la raíz únicamente si la raíz es mas grande que el frame. En este caso luego de ejecutar el código vamos manualmente a ampliar el tamaño de la ventana raíz para ver la diferencia de colores entre el frame y la raíz.

from tkinter import *

raiz=Tk()
raiz.title('Personalizando frames')
#raiz.resizable(0,0)
raiz.iconbitmap('python_icon.ico')
#raiz.geometry('800x600')
raiz.config(bg='dark gray')
frame_raiz=Frame()
frame_raiz.config(width=800,height=600)
frame_raiz.config(bg='light gray')
frame_raiz.pack()  

raiz.mainloop()

Resultado luego de ejecución y ampliación del área de la raíz:



Como se puede ver el tono gris oscuro pertenece al fondo de la raíz mientras que el tono gris claro pertenece a fondo del frame y es visible solamente por que se ha expandido el borde de la ventana, ya que originalmente el frame forza a la ventana a expandirse a su tamaño. Es importante destacar que por defecto el frame no cambia de tamaño para adaptarse a la raíz, sin embargo la raíz si se adapta al frame. Estos comportamientos se pueden modificar. El comportamiento del frame se puede cambiar en el método del empaquetado como un argmento del mismo. Veamos el siguiente ejemplo:

from tkinter import *

raiz=Tk()
raiz.title('Personalizando frames')
#raiz.resizable(0,0)
raiz.iconbitmap('python_icon.ico')
#raiz.geometry('800x600')
raiz.config(bg='dark gray')
frame_raiz=Frame()
frame_raiz.config(width=640,height=480)
frame_raiz.config(bg='light gray')
frame_raiz.pack(side='left')

raiz.mainloop()

Por defecto el frame siempre va a quedar centrado en la raíz, sin embargo en el ejemplo anterior se ha especificado en el empaquetado del frame la opción que se quede siempre fijo del lado izquierdo con el argumento SIDE='LEFT', no importa hacia que lado se expanda la raíz. Por supuesto este parámetro admite las opciones right top y bottom de igual manera. el resultado del código anterior es:


Si deseamos combinar 2 opciones de anclaje del frame, por ejemplo arriba y a la izquierda, se hace necesario agregar un argumento adicional llamado anchor, éste argumento es pasado a través de un parámetro que admite los valores n,s,e,w. Los cuales corresponden a las palabras norte, sur este y oeste en inglés. (north, south, east, west). Veamos el siguiente ejemplo:

from tkinter import *

raiz=Tk()
raiz.title('Personalizando frames')
#raiz.resizable(0,0)
raiz.iconbitmap('python_icon.ico')
#raiz.geometry('800x600')
raiz.config(bg='dark gray')
frame_raiz=Frame()
frame_raiz.config(width=640,height=480)
frame_raiz.config(bg='light gray')
frame_raiz.pack(side='bottom', anchor='e')

raiz.mainloop()

Resultado:


Como podemos comprobar, sin importar hacia que lado se expanda la raíz, el frame siempre va a estar anclado abajo y a la derecha. Otra posible configuración del frame es la de automaticamente rellenar una de las coordenadas, es decir rellenar en el eje X o en el eje Y. PAra rellenar en el eje X basta con agregar el argumento FILL=X, sin embargo para rellenar en el eje Y es necesario usar el argumento FILL=Y y EXPAND = TRUE. Veamos el siguiente ejemplo:

from tkinter import *

raiz=Tk()
raiz.title('Personalizando frames')
#raiz.resizable(0,0)
raiz.iconbitmap('python_icon.ico')
#raiz.geometry('800x600')
raiz.config(bg='dark gray')
frame_raiz=Frame()
frame_raiz.config(width=640,height=480)
frame_raiz.config(bg='light gray')
frame_raiz.pack(fill=Y,expand=True)

raiz.mainloop()


Resultado:

Como podemos comprobar, por mas que se expanda la raíz hacia abajo, el frame siempre va a rellenar el espacio en ese sentido auque no lo haga en la horizontal. Veamos el ejemplo de relleno automático en el eje X:

from tkinter import *

raiz=Tk()
raiz.title('Personalizando frames')
#raiz.resizable(0,0)
raiz.iconbitmap('python_icon.ico')
#raiz.geometry('800x600')
raiz.config(bg='dark gray')
frame_raiz=Frame()
frame_raiz.config(width=640,height=480)
frame_raiz.config(bg='light gray')
frame_raiz.pack(fill=X)

raiz.mainloop()

Resultado:


Como podemos comprobar en este caso el frame se expande solamente en el eje X, nótese que no hace falta en este caso usar el parámetro EXPAND=TRUE. Nota, para que se expanda en ambas direcciones basta con usar el parámetro FILL=BOTH con EXPAND=TRUE. Veamos el código:

from tkinter import *

raiz=Tk()
raiz.title('Personalizando frames')
#raiz.resizable(0,0)
raiz.iconbitmap('python_icon.ico')
#raiz.geometry('800x600')
raiz.config(bg='dark gray')
frame_raiz=Frame()
frame_raiz.config(width=640,height=480)
frame_raiz.config(bg='light gray')
frame_raiz.pack(fill=BOTH,expand=True)

raiz.mainloop()

El resultado es:


A pesar de no verse en la imagen, el frame se expande en ambos sentidos sin importar cuanto se cambie el tamaño de la raíz.

Por último para este aparado, podemos modificar también el tipo de borde del frame, a través del parámetro RELIEF. Las opciones que admite son: FLAT, RAISED, SUNKEN, GROOVE y RIDGE. A saber plano, elevado, hundido, zanjado y cresta respectivamente. Nota: para que sea visible el efecto de borde hay que definir un ancho con el parámetro BORDER, asignando un valor lo suficientemente grande para que el efecto sea visible. Veamos un ejemplo:

from tkinter import *

raiz=Tk()
raiz.title('Personalizando frames')
#raiz.resizable(0,0)
raiz.iconbitmap('python_icon.ico')
#raiz.geometry('800x600')
raiz.config(bg='dark gray')
frame_raiz=Frame()
frame_raiz.config(width=640,height=480)
frame_raiz.config(bg='light gray',border=12,relief=RIDGE)
frame_raiz.pack()

raiz.mainloop()

Resultado:


El cursor de la ventana y del frame también son personalizables, con el parámetro CURSOR, dentro los posibles se encuentran arrow, circle, cross, heart, man, spider, star, trek, watch. Se puede ver la lista completa en este enlace. Veamos el siguiente ejemplo:

from tkinter import *

raiz=Tk()
raiz.title('Personalizando frames')
#raiz.resizable(0,0)
raiz.iconbitmap('python_icon.ico')
#raiz.geometry('800x600')
raiz.config(bg='dark gray')
frame_raiz=Frame()
frame_raiz.config(width=640,height=480)
frame_raiz.config(bg='light gray',border=12,relief=RIDGE,cursor='clock')
frame_raiz.pack()

raiz.mainloop()

Como nota adicional hay que mencionar que toda la configuración aplicable al frame también es aplicable a la raíz.

Labels

Un label son etiquetas de texto estático. Su ínica función es exactamente eso, mostrar texto estático. Se deben declarar con la siguiente sintaxis:

<variable de etiqueta>=LABEL(<nombre del contenedor>,opciones)

Siendo el nombre del contenedor el widget donde deseamos que este anclada la etiqueta de texto. PAra ver las opciones ver este enlace. Es importante destacar que los objetos de la clase LABEL también se deben empaquetar con el método PACK(). Veamos el siguiente ejemplo:

from tkinter import *
#Creación de la raíz
raiz=Tk()
raiz.title('Creando labels')
raiz.geometry('800x600')
raiz.config(bg='dark gray')
#Creación del frame
frame_raiz=Frame(raiz)
frame_raiz.config(width=640,height=480)
frame_raiz.config(bg='light gray')
frame_raiz.pack(side=LEFT,anchor=N)
#Creación de los labels
lblEtiqueta01=Label(frame_raiz,text='Primera etiqueta de texto creada en Python')
lblEtiqueta01.pack()

raiz.mainloop()

Resultado:


Podemos observar que aparece la etiqueta con el texto definido, pero a pesar de haber definido un tamaño determnado para el frame, éste se reduce al tamaño del elemento contenido al ejecutarse el empaquetamiento. Para solucionar esto basta con sustituir el método PACK() por el método PLACE(), especificando las coordenadas en pixeles donde se desea colocar la etiqueta. Veamos el siguiente ejemplo:

from tkinter import *
#Creación de la raíz
raiz=Tk()
raiz.title('Colocando labels')
raiz.geometry('800x600')
raiz.config(bg='dark gray')
#Creación del frame
frame_raiz=Frame(raiz)
frame_raiz.config(width=640,height=480)
frame_raiz.config(bg='light gray')
frame_raiz.pack(side=LEFT,anchor=N)
#Creación de los labels
lblEtiqueta01=Label(frame_raiz,text='Primera etiqueta de texto creada en Python',bg='light gray')
lblEtiqueta01.place(x=10,y=10)

raiz.mainloop()

Resultado:



Como podemos observar ahora aparece la etiqueta en el lugar especificado por el método PLACE().

Es posible abreviar la declaración de etiquetas omitiendo la declaración de variables tipo label. Veamos otra manera de efectuar la operación anterior sin el uso de variables:

from tkinter import *
#Creación de la raíz
raiz=Tk()
raiz.title('Colocando labels')
raiz.geometry('800x600')
raiz.config(bg='dark gray')
#Creación del frame
frame_raiz=Frame(raiz)
frame_raiz.config(width=640,height=480)
frame_raiz.config(bg='light gray')
frame_raiz.pack(side=LEFT,anchor=N)
#Creación de los labels
# lblEtiqueta01=Label(frame_raiz,text='Primera etiqueta de texto creada en Python',bg='light gray')
# lblEtiqueta01.place(x=10,y=10)
Label(frame_raiz,text='Etiqueta sin el uso de variables',bg='light gray').place(x=1,y=1)

raiz.mainloop()

Resultado:


Uso de imágenes en labels

Es posible con la librería de TKINTER el uso de imágenes en lugar de texto en etiquetas, hay que aclarar que soamente admite los formatos .PNG y .GIF. Para usar otros formatos es necesario el uso de librerias adicionales. Para usar imágenes en etiquetas es necesario primero recurrir a la clase PHOTOIMAGE(), la cual permite asignar un archivo de imagen a una variable. La sintaxis de esta clase es como sigue:

<nombre de variable de imagen> = PHOTOIMAGE('<nombre del archivo de imagen GIF o PNG>')

Posteriormente se usa el método LABEL como vimos en el caso del texto, pero sin usar el parámetro TEXT= y en su lugar usar el parámetro IMAGE=. Veamos el siguiente ejemplo:

from tkinter import *
#Creación de la raíz
raiz=Tk()
raiz.title('Colocando labels')
raiz.geometry('800x600')
raiz.config(bg='dark gray')
#Creación del frame
frame_raiz=Frame(raiz)
frame_raiz.config(width=640,height=480)
frame_raiz.config(bg='light gray')
frame_raiz.pack(side=LEFT,anchor=N)
#Creación de los labels de imagenes
imgPython=PhotoImage(file='Python_img.png')
Label(frame_raiz,image=imgPython).place(x=0,y=0)

raiz.mainloop()

Resultado:



Como podemos ver se ha creado una etiqueta de imagen colocada en el sitio especificado.

Entry o caja de texto

Las cajas de texto son, como su nombre lo dice, cajas para ingresar texto. Su funcionamiento es muy similar a las etiquetas. Veamos un ejemplo para entrar en materia:

from tkinter import *

raiz=Tk()
raiz.title('Cuadro de texto')
raiz.geometry('800x600')
raiz.config(bg='dark grey')
#declaración frame
frame_raiz=Frame(raiz)
frame_raiz.config(bg='light gray')
frame_raiz.config(borderwidth=1,relief='solid',width=640,height=480)
frame_raiz.pack(expand=True,fill=BOTH,padx=2,pady=2)
#Declaración textbox
tbCuadroTexto01=Entry(frame_raiz)
tbCuadroTexto01.pack()

raiz.mainloop()

Resultado: 




Podemos comprobar que se ha creado un cuadro de texto dentro del objeto fram_raiz. Por defecto TKINTER lo coloca centrado y en la parte superior. Caabe menckionarquese ha usado la propiedad PADX y PADY para dejar un pequeño margen de 2 pixeles entre frame_raiz y raiz.

Podemos al igual que con el widget anterior, usar el método PLACE() para colocar el cuadro de texto en una coordenada específica demtro de su contenedor, por ejemplo si deseamos que deje 1 pixel del lado izquierdo y 1 pixel del lado superior podemos hacero de la siguiente manera:

from tkinter import *

raiz=Tk()
raiz.title('Cuadro de texto')
raiz.geometry('800x600')
raiz.config(bg='dark grey')
#declaración frame
frame_raiz=Frame(raiz,width=800,height=600,borderwidth=1,relief='solid',bg='light gray')
frame_raiz.pack(expand=True,fill=BOTH,padx=2,pady=2)
#Declaración textbox
tbCuadroTexto01=Entry(frame_raiz)
tbCuadroTexto01.place(x=2,y=2)

raiz.mainloop()

Resultado:


Como podemos cmoprobar ahora el cuadro de texto se ha posicionado en las coordenadas que se han especificado. Hay que recordarque al usar el método PLACE() se debe eliminar el método PACK().

Si desearamos incluir mas de un widget en un mismo contenedor, cosa que es muy común, nos encontraríamnos con el problema que se hace muy engorroso manejar coordenadas e ir moviendo pixel a pixel cada elemento para que quede legible, presentable y estético, ademas que se pierde mucho tiempo en ensayo y error. Veamos el siguiente ejemplo:

from tkinter import *

raiz=Tk()
raiz.title('Cuadro de texto')
raiz.geometry('800x600')
raiz.config(bg='dark grey')
#declaración frame
frame_raiz=Frame(raiz,width=800,height=600,borderwidth=1,relief='solid',bg='light gray')
frame_raiz.pack(expand=True,fill=BOTH,padx=2,pady=2)
#Declaración label
lblEtiqueta01 = Label(frame_raiz,text='Nombre:',bg='light gray')
lblEtiqueta01.place(x=1,y=2)
#Declaración textbox
tbCuadroTexto01=Entry(frame_raiz)
tbCuadroTexto01.place(x=60,y=2)

raiz.mainloop()

Resultado:


Este sería la típica combinación etiqueta y cuadro de texto para ingrersar información por pantalla bajo  Windows.

Método GRID()

Sin embargo existe una manera mucho más práctica de colocar los elementos en pantalla, usando el método GRID(). El método GRID() perminte manejar una grilla virtual compuesta por filas y columnas cuyas coordenadas comienzan por 0,0, siendo este cuadro inicial el equivalente a la esquina superior izquierda. Veamos el siguiente ejemplo:

from tkinter import *

raiz=Tk()
raiz.title('Uso de grid')
raiz.geometry('800x600')
raiz.config(bg='dark grey')
#declaración frame
frame_raiz=Frame(raiz,width=800,height=600,borderwidth=1,relief='solid',bg='light gray')
frame_raiz.pack(expand=True,fill=BOTH,padx=2,pady=2)

#Declaración label
lblEtiqueta01 = Label(frame_raiz,text='Nombre:',bg='light gray')
lblEtiqueta01.grid(row=0,column=0)

#Declaración textbox
tbCuadroTexto01=Entry(frame_raiz)
tbCuadroTexto01.grid(row=0,column=1)

raiz.mainloop()

Resultado:


Como podemos ver efectivamente se ha colocado los elementos en la grilla como se ha especificado. Ahora coloquemos mas elementos del formulario con el usop del método GRID().

from tkinter import *

raiz=Tk()
raiz.title('Uso de grid')
raiz.geometry('800x600')
raiz.config(bg='dark grey')
#declaración frame
frame_raiz=Frame(raiz,width=800,height=600,borderwidth=1,relief='solid',bg='light gray')
frame_raiz.pack(expand=True,fill=BOTH,padx=2,pady=2)

#Nombre
lblEtiquetaNombre = Label(frame_raiz,text='Nombre:',bg='light gray')
lblEtiquetaNombre.grid(row=0,column=0)
tbCuadroNombre=Entry(frame_raiz)
tbCuadroNombre.grid(row=0,column=1)

#Apellido
lblEtiquetaApellido = Label(frame_raiz,text='Apellido:',bg='light gray')
lblEtiquetaApellido.grid(row=1,column=0)
tbCuadroApellido=Entry(frame_raiz)
tbCuadroApellido.grid(row=1,column=1)

#Dirección
lblEtiquetaDirección = Label(frame_raiz,text='Dirección:',bg='light gray')
lblEtiquetaDirección.grid(row=2,column=0)
tbCuadroDireccion=Entry(frame_raiz)
tbCuadroDireccion.grid(row=2,column=1)

raiz.mainloop()

Resultado:


Podemos comprobar como el uso de la grilla facilita muchísimo la colocacón de elementos en la creación de un formulario.




Comentarios

Entradas populares