Fundamentos de POO para interfaces gráficas en Python

Primer programa con Tkinter

De las tres bibliotecas que utilizaremos en este curso, Tkinter es la única que en principio viene preinstalada, es por decirlo de alguna forma la biblioteca oficial de Python para crear interfaces gráficas.

Si bien es bastante simple y fácil de empezar a utilizar, por contra ofrece pocos elementos gráficos y un control limitado sobre el comportamiento de la interfaz. Además su principal es que en realidad se trata de un puente para usar otra biblioteca gráfica llamada Tcl/Tk en Python. Eso hace que carezca en sí misma de una documentación en condiciones y si quieres profundizar en sus componentes tienes que acabar consultando la documentación oficial de Tcl/Tk, cuya presentación digamos que no es muy amigable.

En fin, vamos a crear nuestro programa de ejemplo a ver qué podemos aprender de él:

hola_tk.py

# Todos los componentes se encuentran en este módulo
import tkinter as tk  

# Tk es la clase que crea el componente raíz o ventana principal
app = tk.Tk()   
# Su método mainloop() inicia el bucle infinito del programa
app.mainloop()  

El componente raíz es una ventana en sí misma, pero no tiene ningún contenido. Si queremos añadir algo dentro tendremos que crear otros componentes y añadirlos dentro, por ejemplo un botón:

# Al instanciarlo el primer argumento indica el contenedor
button = tk.Button(app, text="Hola")  

Sin embargo en tkinter no es suficiente con crear un componente y añadirlo al contenedor, tenemos que posicionarlo:

# Podemos usar el método pack para empaquetarlo en su contenedor
button.pack()

Como veis ya aparece nuestro botón, pero curiosamente la ventana se ha estrechado. Eso es porque el componente raíz no tiene tamaño propio.

Para añadirle un tamaño por defecto podemos usar el método geometry:

# Esto le dará 100px de ancho por 50 de alto
app.geometry("100x50")  

Ahora nos falta añadirle la funcionalidad al botón para que al presionarlo se muestre un mensaje en la terminal. Para hacer necesitaremos enlazar una función como comando del botón y tendremos que definirla antes de enlazarla porque sino no se encontrará su referencia:

def hola():
    print("¡Hola mundo!")

# ...

button = tk.Button(app, text="Hola", command=hola)

Con esto ya tenemos nuestro programa "Hola Mundo" con Tkinter, sin embargo se trata de una estructura poco reutilizable y tener que definir las funciones antes no es muy práctico.

Podemos solucionar estos problemas adaptando el ejemplo para que use programación orientada a objetos bajo nuestra propia lógica:

import tkinter as tk


class MainWindow:
    # Le pasamos el componente raíz al constructor
    def __init__(self, root):
        # Establecemos el tamaño de la raíz
        root.geometry("100x50")
        # Añadimos el botón y lo empaquetamos
        button = tk.Button(root, text="Hola", command=self.hola)
        button.pack()

    # Definimos la función como un método de clase
    def hola(self):
        print("¡Hola mundo!")


# Creamos la aplicación, la ventana e iniciamos el bucle
app = tk.Tk()
window = MainWindow(app)
app.mainloop()

Con esto ya lo tenemos.

¿Qué os ha parecido? No os sintáis abrumados por tantos nuevos conceptos, hacedme caso.

Lo importante es que entendáis el flujo del programa. ¿Sabríais determinar cuales son las clases que se están usando? ¿Los métodos y atributos?

Si es así no temáis nada, la mayoría de las veces la programación no se trata de memorizar instrucciones, sino intuir qué necesitas y buscar en la documentación o en algún ejemplo hasta que das con esa instrucción. Leed documentación, tutoriales, ejemplos... haced pequeños experimentos practicando lo que vais aprendiendo, esa es la clave para dominar cualquier tema.

Os dejaré algunos enlaces de documentación en los apuntes por si queréis profundizar más sobre Tkinter: