Programación de interfaces gráficas con tkinter
Los aspectos fundamentales
Una de las librerías más populares en Python para crear interfaces gráficas, se llama tkinter, aunque hay otras, en particular, GTK y QT, utilizadas como base de los entornos de escritorio Gnome y KDE respectivamente. Esta librería proviene de un lenguaje de programación llamado Tcl, lenguaje de programación que fue muy popular y apreciado durante los años 2000. De esta manera, la librería tkinter es ideal en el contexto de la Raspberry Pi para diseñar rápidamente interfaces gráficas que tengan un bajo consumo en términos de recursos. Como prueba, el editor de código IDLE, que se presentó a lo largo del capítulo Entorno de programación, está programado con tkinter. Para familiarizarse rápidamente con esta librería, se presentan ejemplos como de costumbre, del más sencillo al más complicado.
Desde un punto de vista teórico, una aplicación tkinter se descompone en varias capas. La capa básica representa la ventana de la aplicación tal y como aparece en pantalla. La clase Tk es el componente gráfico que obligatoriamente se debe inicializar durante el arranque de cada aplicación que utilice la librería. En esta capa se añaden y acumulan a continuación otros componentes gráficos, que permiten interactuar con la ventana, como botones...
Proyecto #1: Hello world con tkinter
¿Qué mejor que escribir el tradicional ejemplo Hello world para presentar los componentes de la librería? Por el momento, solo se revisan tres: Label para los campos de texto, Button para los botones y Frame para los marcos que necesitan una disposición particular. El código más básico que ilustra un Hello world con tkinter se resume en estas pocas líneas (Capitulo_7/hello_1.py):
1 #!/usr/bin/env python3
2 import tkinter
3 from tkinter import *
4 ventana = tkinter.Tk()
5 ventana.geometry('300x150')
6 etiqueta = Label(ventana, text='Hello world con tkinter.')
7 label.pack()
8 ventana.mainloop()
Aquí, el componente gráfico Label crea una zona en la que se puede escribir texto. Observe la manera en la que se crea el widget. En efecto, el primer argumento corresponde a la ventana o el marco en el que se añade el componente gráfico. Una vez creado el elemento, un administrador de geometría se hace cargo y ubica los elementos en la ventana. La llamada a la función pack() invoca al administrador de geometría Pack, que centra el campo de texto en el centro de la ventana. Durante la ejecución del script, aparece una ventana con texto:
Sin embargo, la librería cuenta con otros dos administradores de geometría. Siempre utilizando el ejemplo Hello world, a continuación se muestra cómo funciona el administrador Place para ubicar un elemento en un lugar concreto en la ventana tkinter...
Proyecto #2: un visor de imágenes
Un visor de imágenes sirve fundamentalmente para visualizar imágenes. Por lo tanto, el objetivo de este proyecto es crear una ventana en la que se muestre una imagen. Una aplicación útil en efecto, porque este visor mostrará quizás sus últimas fotos de vacaciones…
Antes de empezar a trabajar en este proyecto, en primer lugar es necesario descargar un componente necesario para escribir esta aplicación. En efecto, la librería incorpora por defecto el componente gráfico PhotoImage para mostrar imágenes. Sin embargo, los formatos de imagen soportados por la librería son limitados, porque el componente solo puede mostrar imágenes en formato GIF, PPM y PGM. Sin embargo, gracias a Pillow, una librería muy utilizada para la manipulación de imágenes y que se aborda en el siguiente capítulo, los desarrolladores de tkinter han podido extender las capacidades de PhotoImage para mostrar otros formatos, como JPEG o PNG.
Para reflejar este cambio en su Raspberry Pi, es necesario descargar el paquete python3-pil.imagetk. A continuación se muestra qué es necesario hacer desde una shell:
pi@raspberrypi:~ $ sudo su -
root@raspberrypi:~# apt-get install python3-pil.imagetk
La herramienta apt-get le pide confirmar que este paquete realmente se debe instalar, confirmación a la que será necesario responder que sí. Una vez instalado el paquete, verifique que el módulo efectivamente está disponible y presente en la Raspberry Pi, escribiendo en una consola Python:
>>> from PIL import ImageTk
Si la importación se ejecuta sin ningún error, quiere decir que el módulo se ha instalado correctamente. Colóquelo en el código.
El código del visor se organiza dentro de una clase, llamada PiVision. La arquitectura de este proyecto empieza por las importaciones necesarias y la definición del constructor de la clase (Capitulo_7/visor_1.py):
1 #!/usr/bin/env python3
2 from tkinter import *
3 import glob, sys, os
4
5 class PiVision(Tk):
6 def __init__(self, imagenes):
La clase PiVision hereda de la clase Tk. En efecto, heredando de la ventana principal, y colocando un contenedor de imágenes, un sencillo Label en realidad...
Proyecto #3: un editor de texto
El editor de texto es la mejor compañía del programador. La librería tkinter contiene todos los ingredientes necesarios para escribir su propio editor, usando cerca de 150 líneas. Extremadamente ligero para su uso en la Raspberry Pi. Evidentemente, todas las funcionalidades de un editor de texto clásico no están cubiertas, tales como la coloración sintáctica, la gestión de los tipos de letra o la impresión. Sin embargo lo principal queda cubierto y se resume en: abrir un archivo (nuevo o existente), editar su contenido y guardar los cambios.
El nombre que se da a este proyecto será PiDitor. El proyecto empieza por la tradicional importación de los módulos necesarios (Capitulo_7/editor_1.py):
1 #!/usr/bin/env python3
2 from tkinter.filedialog import asksaveasfilename
3 from tkinter.filedialog import askopenfilename
4 from tkinter.simpledialog import askstring
5 from tkinter.messagebox import *
6 from tkinter.scrolledtext import *
7 from tkinter import *
8 import os, sys
Además de los tradicionales componentes gráficos explicados hasta ahora, la librería ofrece un panel de ventanas y pop-ups pre-programados, con el objetivo de evitar tener que reinventar la rueda.
La clase principal tiene el mismo nombre que la del editor y encapsula la lógica de construcción del editor de texto:
10 class PiDitor(Frame):
11 def __init__(self, parent=None, nombre_archivo=None):
12 Frame.__init__(self, parent)
13 self.pack(expand=YES, fill=BOTH)
14 self.archivo_actual = nombre_archivo
15 self.nombre_editor = self.__class__.__name__
16 self.crear_componentes()
17 self.administrar_eventos()
18 self.mostrar_archivo(nombre_archivo)
El editor se puede inicializar pasando como argumento un nombre de archivo. Esta condición se gestiona a lo largo de todo el script:
150 if __name__ == '__main__':
151 if len(sys.argv) > 1:
152 archivo...
Conclusión
La librería tkinter es una candidata perfecta para crear interfaces gráficas ligeras, destinadas a ser utilizadas en la Raspberry Pi. La mayor parte de los proyectos abordados durante este capítulo contienen alrededor de 100 líneas de código por proyecto, para un resultado a menudo inesperado (editor, diapositivas, etc.).