Desarrollo de GUI de Python con Tkinter

    Esta es la primera entrega de nuestra serie de varias partes sobre el desarrollo de GUI en Python usando Tkinter. Consulte los enlaces a continuación para ver las siguientes partes de esta serie:

    • Desarrollo de GUI de Python con Tkinter
    • Desarrollo de GUI de Python con Tkinter: Parte 2
    • Desarrollo de GUI de Python con Tkinter: Parte 3

    Introducción

    Si est√° leyendo este art√≠culo, existe la posibilidad de que sea una de esas personas que aprecian el software operado a trav√©s de una sencilla interfaz de l√≠nea de comandos. Es r√°pido, f√°cil para los recursos de su sistema y probablemente mucho m√°s r√°pido de usar para un virtuoso del teclado como usted. Sin embargo, no es ning√ļn secreto que si queremos llegar a una base de usuarios m√°s amplia con nuestro software, ofrecer solo una soluci√≥n de l√≠nea de comandos puede asustar a una gran parte de los usuarios potenciales. Para la mayor√≠a de las personas, la forma m√°s obvia de interactuar con un programa es utilizar un GUI – un Interfaz gr√°fica del usuario.

    Mientras usa una GUI, el usuario interact√ļa y manipula los elementos de la interfaz llamada widgets. Algunos widgets, como botones y casillas de verificaci√≥n, permiten al usuario interactuar con el programa. Otros, como Windows y marcos, sirven como contenedores para otros widgets.

    Hay muchos paquetes para construir GUI en Python, pero solo hay uno de esos paquetes que se considera un estándar de facto y se distribuye con todas las instalaciones predeterminadas de Python. Este paquete se llama Tkinter. Tkinter es el enlace de Python a Tk Рun conjunto de herramientas de GUI multiplataforma de código abierto.

    Creando tu Primera Ventana

    Como se mencionó anteriormente, Tkinter está disponible con instalaciones estándar de Python, por lo que independientemente de su sistema operativo, crear su primera ventana debería ser muy rápido. Todo lo que necesita son 3 líneas de código:

    import tkinter
    
    root = tkinter.Tk()
    
    root.mainloop()
    

    Salida:

    Después de importar el tkinter paquete en la línea 1, en la línea 3 creamos el widget de la ventana principal (raíz) de nuestra aplicación. Para que el programa funcione correctamente, solo debe haber un widget de ventana raíz en nuestra interfaz y, debido a que todos los demás widgets estarán más abajo en la jerarquía que la raíz, debe crearse antes que cualquier otro widget.

    En la línea 5, inicializamos la raíz mainloop. Gracias a esta línea, la ventana permanece en un bucle que espera eventos (como la interacción del usuario) y actualiza la interfaz en consecuencia. El bucle termina cuando el usuario cierra la ventana, o un quit() se llama al método.

    Agregar widgets simples a la ventana raíz

    En el siguiente ejemplo, aprenderemos la filosofía general de dos pasos para crear widgets, que se puede aplicar a todos los widgets excepto a las Windows. El primer paso es crear una instancia de la clase de un widget específico. En el segundo paso, tenemos que usar uno de los métodos disponibles para colocar el nuevo widget dentro de otro widget ya existente (un padre widget). El widget más simple que puede poner en su interfaz Tkinter es un etiqueta, que simplemente muestra algo de texto. El siguiente ejemplo crea un widget de etiqueta simple:

    import tkinter
    
    root = tkinter.Tk()
    
    simple_label = tkinter.Label(root, text="Easy, right?")
    
    simple_label.pack()
    
    root.mainloop()
    

    Salida:

    Creamos el Label instancia de clase en la línea 5 del código anterior. En el primer argumento apuntamos al widget padre deseado de la etiqueta, que en este ejemplo es nuestra ventana raíz. En el segundo argumento especificamos el texto que queremos que muestre la etiqueta.

    Luego, en la l√≠nea 7, aplicamos un m√©todo para orientar nuestra etiqueta dentro de la ventana ra√≠z. El m√©todo m√°s simple para orientar los widgets que ofrece Tkinter es pack(). La etiqueta es el √ļnico widget dentro de la ventana, por lo que simplemente se muestra en el medio de la ventana.

    Aprenderemos m√°s sobre c√≥mo funciona en el siguiente ejemplo, cuando agreguemos otro widget a la ventana. Tenga en cuenta que el tama√Īo de la ventana se ajusta autom√°ticamente al widget colocado en su interior.

    Agregar un botón funcional

    Ahora, agreguemos algo con lo que el usuario pueda interactuar. La opción más obvia es un botón simple. Pongamos un botón en nuestra ventana que nos da una forma adicional de cerrar nuestra ventana.

    import tkinter
    
    root = tkinter.Tk()
    
    root.title("Hello!")
    
    simple_label = tkinter.Label(root, text="Easy, right?")
    closing_button = tkinter.Button(root, text="Close window", command=root.destroy)
    
    simple_label.pack()
    closing_button.pack()
    
    root.mainloop()
    

    Salida:

    En la línea 8 creamos nuestro Button instancia de clase de una manera muy similar creamos nuestra etiqueta. Sin embargo, como probablemente pueda ver, agregamos un argumento de comando donde le decimos al programa qué debería suceder después de hacer clic en el botón. En este caso rootsuena dramáticamente destroy() se llama al método, que cerrará nuestra ventana cuando se ejecute.

    En las l√≠neas 10 y 11 usamos nuevamente el pack() m√©todo. Esta vez podemos entenderlo un poco mejor, ya que ahora lo usamos para colocar dos widgets dentro de la ventana. Dependiendo del orden en el que empaquetamos nuestros widgets, el m√©todo simplemente los coloca uno encima del otro, centrados horizontalmente. La altura y el ancho de la ventana se ajustan al tama√Īo de los widgets.

    Probablemente hayas notado otra línea nueva. En la línea 5, especificamos la ventana raíz título. Desafortunadamente, el widget más amplio de nuestra interfaz no es lo suficientemente ancho para que el título de la ventana sea visible. Hagamos algo al respecto.

    Controlar el tama√Īo de la ventana

    Echemos un vistazo a tres nuevas l√≠neas que nos permitir√°n cambiar f√°cilmente el tama√Īo de nuestra ventana.

    import tkinter
    
    root = tkinter.Tk()
    
    root.title("Hello!")
    
    root.resizable(width="false", height="false")
    
    root.minsize(width=300, height=50)
    root.maxsize(width=300, height=50)
    
    simple_label = tkinter.Label(root, text="Easy, right?")
    closing_button = tkinter.Button(root, text="Close window", command=root.destroy)
    
    simple_label.pack()
    closing_button.pack()
    
    root.mainloop()
    

    Salida:

    En la l√≠nea 7 definimos si el usuario del programa debe poder modificar la ventana anchura y altura. En este caso, ambos argumentos se establecen en "false", por lo que el tama√Īo de la ventana depende solo de nuestro c√≥digo. Si no fuera por las l√≠neas 9 y 10, depender√≠a de los tama√Īos de los widgets orientados dentro de la ventana.

    Sin embargo, en este ejemplo, usamos root’s minsize y maxsize m√©todos para controlar los valores m√°ximos y m√≠nimos del ancho y alto de nuestra ventana. Aqu√≠ definimos exactamente qu√© tan ancha y alta se supone que debe ser la ventana, pero te animo a jugar con estas tres l√≠neas para ver c√≥mo funciona el redimensionamiento dependiendo del tama√Īo de nuestros widgets, y de qu√© valores m√≠nimo y m√°ximo definimos.

    Más sobre la orientación de widgets

    Como probablemente ya haya notado, al usar el pack() El método no nos da demasiado control sobre dónde terminan los widgets después de empaquetarlos en sus contenedores principales. Por no decir el pack() El método no es predecible; es solo que, obviamente, a veces arrojar widgets a la ventana en una sola columna, donde se coloca un widget sobre el anterior, no es necesariamente consistente con nuestro sofisticado sentido de la estética. Para esos casos, podemos usar pack() con algunos argumentos inteligentes, o use grid() Рotro método para orientar los widgets dentro de contenedores.

    Primero, quizás demos pack() una oportunidad más. Modificando las líneas 15 y 16 del ejemplo anterior, podemos mejorar ligeramente nuestra interfaz:

    simple_label.pack(fill="x")
    closing_button.pack(fill="x")
    

    Salida:

    De esta manera sencilla le decimos al pack() método para estirar la etiqueta y el botón a lo largo del eje horizontal. También podemos cambiar la forma pack() lanza nuevos widgets dentro de la ventana. Por ejemplo, usando el siguiente argumento:

    simple_label.pack(side="left")
    closing_button.pack(side="left")
    

    Salida:

    Podemos empaquetar widgets en la misma fila, comenzando desde el lado izquierdo de la ventana. Sin embargo, pack() no es el √ļnico m√©todo de orientar los widgets dentro de sus widgets principales. El m√©todo que da los mejores resultados es probablemente el grid() m√©todo, que nos permite ordenar los widgets en filas y columnas. Eche un vistazo al siguiente ejemplo.

    import tkinter
    
    root = tkinter.Tk()
    
    simple_label = tkinter.Label(root, text="Easy, right?")
    another_label = tkinter.Label(root, text="More text")
    closing_button = tkinter.Button(root, text="Close window", command=root.destroy)
    another_button = tkinter.Button(root, text="Do nothing")
    
    simple_label.grid(column=0, row=0, sticky="ew")
    another_label.grid(column=0, row=1, sticky="ew")
    closing_button.grid(column=1, row=0, sticky="ew")
    another_button.grid(column=1, row=1, sticky="ew")
    
    root.mainloop()
    

    Salida:

    Para aclarar un poco este ejemplo, eliminamos las l√≠neas que cambiaron el t√≠tulo y el tama√Īo de la ventana ra√≠z. En las l√≠neas 6 y 8 agregamos una etiqueta m√°s y un bot√≥n m√°s (tenga en cuenta que hacer clic en √©l no har√° nada ya que no le hemos adjuntado ning√ļn comando).

    Sin embargo, lo más importante es pack() fue reemplazado por grid() en todos los casos. Como probablemente pueda descubrir fácilmente, los argumentos column y row definamos qué celda de la cuadrícula ocupará nuestro widget. Tenga en cuenta que si define las mismas coordenadas para dos widgets diferentes, el que se represente más adelante en su código se mostrará encima del otro.

    los sticky El argumento probablemente no sea tan obvio. Usando esta opción podemos pegar los bordes de nuestros widgets a los bordes de sus respectivas celdas de la cuadrícula Рnorteorthern (superior), southern (abajo), mia popa (derecha) y western (izquierda). Lo hacemos pasando una cadena simple que contiene una configuración de letras n, s, e y w.

    En nuestro ejemplo, pegamos los bordes de los cuatro widgets a los bordes este y oeste de sus celdas, por lo tanto, la cadena es ew. Esto da como resultado que los widgets se estiren horizontalmente. Puedes jugar con diferentes configuraciones de esas cuatro letras. Su orden en la cadena no importa.

    Ahora que conoce dos métodos diferentes para orientar los widgets, tenga en cuenta que nunca debe mezclar grid() y pack() dentro del mismo recipiente.

    Marcos

    Windows no son los √ļnicos widgets que pueden contener otros widgets. Para que sus interfaces complejas sean m√°s claras, suele ser una buena idea segregar sus widgets en marcos.

    Intentemos hacer eso con nuestros cuatro widgets simples:

    import tkinter
    
    root = tkinter.Tk()
    
    frame_labels = tkinter.Frame(root, borderwidth="2", relief="ridge")
    frame_buttons = tkinter.Frame(root, borderwidth="2", relief="ridge")
    
    simple_label = tkinter.Label(frame_labels, text="Easy, right?")
    another_label = tkinter.Label(frame_labels, text="More text")
    
    closing_button = tkinter.Button(frame_buttons, text="Close window", command=root.destroy)
    another_button = tkinter.Button(frame_buttons, text="Do nothing")
    
    frame_labels.grid(column=0, row=0, sticky="ns")
    frame_buttons.grid(column=1, row=0)
    
    simple_label.grid(column=0, row=0, sticky="ew")
    another_label.grid(column=0, row=1, sticky="ew")
    
    closing_button.pack(fill="x")
    another_button.pack(fill="x")
    
    root.mainloop()
    

    Salida:

    Repasemos cuidadosamente el ejemplo que se muestra arriba. En las líneas 5 y 6 definimos dos nuevos Frame widgets. Obviamente, en el primer argumento apuntamos a su widget padre, que es la ventana raíz.

    Por defecto, los bordes de los marcos son invisibles, pero digamos que nos gustaría ver dónde están colocados exactamente. Para mostrar sus bordes, tenemos que darles un cierto ancho (en nuestro ejemplo, 2 píxeles) y el estilo de relief (una especie de efecto 3D) en el que se dibujará el borde. Existen 5 estilos de relieve diferentes para elegir Рen nuestro ejemplo, usamos ridge.

    Label y Button las definiciones también se modificaron ligeramente (líneas 8-12). Queríamos colocar nuestras etiquetas en nuestro frame_labels marco y nuestros botones en nuestro frame_buttons marco. Por lo tanto, tuvimos que reemplazar a su padre anterior, root, con sus respectivos nuevos padres marco.

    En las líneas 14 y 15, orientamos los marcos dentro de la ventana raíz usando el grid() método. Entonces, usamos el grid() método para orientar las etiquetas (líneas 17-18), y el pack() método para orientar los botones (líneas 20-21). Las etiquetas y los botones ahora están en contenedores separados, por lo que nada nos impide orientar los widgets utilizando diferentes métodos.

    Windows de nivel superior

    Su interfaz no debe contener más de una ventana raíz, pero puede crear muchas Windows que sean secundarias de la ventana raíz. La mejor forma de hacerlo es mediante el Toplevel clase.

    import tkinter
    
    root = tkinter.Tk()
    
    new_window = tkinter.Toplevel()
    new_window.withdraw()
    
    frame_labels = tkinter.Frame(root, borderwidth="2", relief="ridge")
    frame_buttons = tkinter.Frame(root, borderwidth="2", relief="ridge")
    
    simple_label = tkinter.Label(frame_labels, text="Easy, right?")
    another_label = tkinter.Label(frame_labels, text="More text")
    
    closing_button = tkinter.Button(frame_buttons, text="Close window", command=root.destroy)
    window_button = tkinter.Button(frame_buttons, text="Show new window", command=new_window.deiconify)
    
    frame_labels.grid(column=0, row=0, sticky="ns")
    frame_buttons.grid(column=1, row=0)
    
    simple_label.grid(column=0, row=0, sticky="ew")
    another_label.grid(column=0, row=1, sticky="ew")
    
    closing_button.pack(fill="x")
    window_button.pack(fill="x")
    
    root.mainloop()
    

    En el ejemplo anterior, creamos nuestra nueva ventana en la l√≠nea 5. Debido a que una ventana es una entidad que no est√° anclada dentro de ning√ļn otro widget, no tenemos que apuntar a su padre ni orientarlo dentro de un widget padre.

    Nos gustaría mostrar la nueva ventana después de presionar un botón. La línea 5 lo muestra de inmediato, por lo que usamos el withdraw() en la línea 6 para ocultarlo. Luego modificamos la definición del botón en la línea 15.

    Aparte del nuevo nombre y texto de la variable, el botón ahora ejecuta un comando: el new_window método del objeto, deiconify, que hará que la ventana vuelva a aparecer después de que el usuario haga clic en window_button botón.

     

    GUI de Python: de la A a la Z

    ¬ŅDesea obtener m√°s informaci√≥n sobre c√≥mo crear GUI en Python y las herramientas disponibles para usted, como Tkinter? ¬°Intente realizar un curso de formaci√≥n paso a paso para ense√Īarle c√≥mo crear r√°pidamente GUI para sus aplicaciones!

     

    Conclusiones

    Como puede ver, con Tkinter puede crear GUI de manera f√°cil y r√°pida para usuarios no expertos de su software. La biblioteca est√° incluida en todas las instalaciones de Python, por lo que construir su primera ventana simple est√° a solo un par de l√≠neas de c√≥digo. Los ejemplos que se muestran arriba apenas ara√Īan la superficie de las capacidades del paquete.

    Etiquetas:

    Deja una respuesta

    Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *