Aplicaciones de escritorio en Python
Python se ha convertido en una buena opción para desarrollar aplicaciones de escritorio a través a librerías gráficas como GTK, WxWidgets, Qt, etc.. todas ellas escritas en C/C++ siendo multiplataforma y de código abierto.
Es muy importante que aprendamos a desarrollar aplicaciones de escritorio o gráficas de forma manual en Python, es decir, escribir el código directamente. Esto nos permite aprender y aumentar nuestros conocimientos en este lenguaje, no depender de otras aplicaciones que no sepamos su funcionamiento y a realizar diversas prácticas de desarrollo, pentesting, trabajos, etc..
Table of Contents
ToggleMódulo tkinter
En este apartado veremos cómo desarrollar aplicaciones de escritorio con Python paso a paso, a través del siguiente repositorio en github. Para ello haremos uso de la librería tkinter (Tcl/Tk) ya que, si bien es pequeña en comparación con las mencionadas anteriormente, posee las herramientas necesarias para su correcto uso y generar aplicaciones de escritorio en poco tiempo. También, cabe mencionar, que accederemos a ella a través del módulo tcl/tk que viene instalado por defecto en Python, por lo que no será necesario llevar a cabo instalaciones externas.
Veamos la siguiente imagen:
Podemos observar una de las tantas aplicaciones de escritorio hecha en Python con el módulo tcl/tk. También, se puede apreciar los diferentes Widgets que posee (menúes, cajas de texto, etiqueta, botones, etc.). Incluso la misma ventana es un widget.
Debemos tener en cuenta que el módulo tkinter sigue el paradigma de programación orientada a objetos, es decir, su estructura está basada de la siguiente forma:
mi_objeto = mi_Clase()
Por lo tanto, decimos que mi_objeto es una instancia de mi_Clase(). Puesto que cada widget de Tcl/Tk es una clase, tendrán nombres que sigan esa convención.
Estructura de Aplicación
Lo primero que haremos será importar los módulos tkinter y ttk. Este último es muy importante, ya que introduce algunos widgets nuevos a las colecciones de Tcl/Tk y optimiza otros ya existentes en el primero.
Import tkinter as tk
from tkinter import ttk
Vemos que hemos importado tkinter como “tk”. Esto se suele hacer por convencion y eso explica el funcionamiento de as.
Una aplicación debe poseer una ventana principal, por tanto, siempre es lo primero que se debe crear. Lo haremos de la siguiente forma:
ventana_pr = tk.Tk()
ventana_pr.title(“Proyecto – Aplicación”)
ventana_pr.config(width=300, hieght=200)
ventana_pr.mainloop()
Algo importante que debemos tener en cuenta hasta es el tamaño de la ventana ya que será fundamental para colocarle los widgets más adelante. Esto se realiza a través de la función config() o configure() con aproximadamente 300px de ancho y 200px de alto.
La función mainloop() permite ejecutar el bucle principal de la aplicación, aquel encargado de dibujar todos los controles y manejar los eventos (los cuales detallaremos más adelante). Podemos notar que esta función bloquea la ejecución del código hasta que la ventana principal se cierra, es decir, hasta que hacemos click en la cruz roja. Recuerde colocar dicha función al final del código siempre, y así evitar posibles problemas.
Widgets básicos
Luego de haber configurado la ventana, dentro de ella vamos a colocar algunos controles a través de la función place(), que toma cuatro argumentos: la posición (x, y, tomando el origen de coordenadas en el extremo superior izquierdo) y el tamaño (width, height). Esto será fundamental para el uso de widgets y todos los temas que vamos a estar abarcando.
Ahora bien, vamos a interactuar con los widgets más básicos, estos son: Botón, Caja y Etiqueta. Luego usaremos otros un poco más avanzados.
Botón
El módulo tk nos provee dos widgets para botones, estos son: ttk.Button, el cual se lo denomina como uso básico,y tk.Button, cuyas mejoras pueden apreciarse. Veamos algunos ejemplos:
boton = ttk.Button(text=“Esto es un ejemplo”)
boton.place(x=10, y=10)
El código anterior genera un botón con el texto “Esto es un ejemplo” cuya posición en x es 10 y en y es 20. El parámetro text indica el texto que mostrará el botón. En caso de omitir valores width y height en una llamada a place(), estos serán inferidos de acuerdo con la longitud del texto.
Si deseamos asociar la presión del botón con una función en Python, podemos hacer lo siguiente:
def boton_presionar():
pass
Teniendo esto en cuenta, en la aplicación deberemos usar el parámetro command. Por ejemplo:
boton = ttk.Button(text=“Esto es un ejemplo”, command=boton_presionar)
boton.place(x=10, y=10)
En caso de querer configurar o modificar algún argumento al generar un widget, podemos hacerlo vía config(). Por ejemplo, si deseamos cambiar el texto del botón en otro lugar del programa, haremos:
boton.config(text=“Nuevo ejemplo”)
Por lo tanto, hasta aquí ya hemos visto como crear una ventana, un botón y cómo asociarlo a la función de Python cuando se lo presiona.
Cajas de Texto
Estos widgets, también llamados entry y text, se encuentran en este módulo de dos maneras: tk.Entry y tk.Text. El primero suele ser útil para textos pequeños en una primera línea, soportanto solo texto plano. El segundo puede albergar imágenes y texto con formato, como así también, permitir texto de múltiples líneas. Su sintaxis es:
entry = ttk.Entry()
Hasta aquí, ¿Recordará qué función debemos usar para que el usuario obtenga el texto, no? ¡Exacto! Debemos introducir get(). Veamos un ejemplo en el que una función asociada a un botón, toma lo que hay en la caja:
def imprimir_texto():
print(entry.get())
Por lo tanto, tendríamos en la aplicación:
entry = ttk.Entry()
entry.place(x = 160, y = 10)
boton = ttk.Button(text = “Imprimir texto”)
boton.place(x = 10, y = 50)
Llegando hasta aquí, en el caso de querer insertar o remover texto de cierta posición, lo haremos vía las funciones insert() y delete().
Si deseamos borrar los primeros 5 caracteres:
entry.delete(0, 5)
En el caso de querer ingresar texto al comienzo del control:
entry.insert(0, “Esto es un ejemplo”)
Para borrar todo el texto:
entry.delete(0, tk.END)
Por tanto, nuestra ventana quedaría de la siguiente manera:
Etiqueta
Las etiquetas, también llamas label, tiene como funcionalidad contener una imagen o un texto. La propiedad que controla dicha función, al igual que los botones, es text.
etiqueta = ttk.Label(text = “Es es un ejemplo de etiqueta”)
etiqueta.place(x=100, y=50)
En el caso de querer modificar el tamaño de algún widget, tendríamos que usar las funciones widht y height. Por ejemplo, si queremos modificar el tamaño de la caja de texto haríamos:
entry = ttk.Entry()
entry.place(x = 160, y = 10, widht=150, y=25)
Tipos de Listas
Lista común o Listbox
Esta lista nos permitirá mostrar un conjunto de texto como se vé en la siguiente imagen:
Para crear una lista, primero debemos generar una instancia de la clase tk.Listbox e insertamos elementos vía insert().
lista = tk.Listbox()
lista.insert(0, “Lenguajes:”, “Python”, “C++”, “Java”)
lista.place(x=10, y=10)
Podemos notar que el primer argumento de la función insert() indica la posición en la que se debe indicar un elemento. Recordemos que en Python, el primer elemento comienza a partir del cero. También, podemos usar tk.END para indicar el final de la lista:
lista.insert(tk.END, “Último elemento”)
Ahora bien, debemos tener en cuenta que la función get() retorna el elemento en una posición determinada, mientras que curlselection() la posición del elemento que se ha seleccionado, es decir, la opción seleccionada por el cursor de la lista. Por ejemplo:
def imprimir_seleccion():
op_cursor =(lista.get(lista.curselection()))
print(op_cursor)
Este código se encargará de imprimir en pantalla los lenguajes a medida que los vayamos seleccionando. Por tanto, en la aplicación deberíamos de contar con un botón cuyo comando sea “imprimir_seleccion”.
Out:
Go
C++
Python
Java
Lista desplegable o Combobox
Una lista desplegable es una combinación entre una lista común y una caja de texto (Entry). Cuya función es permitir seleccionar varios elementos, o también, ingresar de forma manual un texto. Observemos la siguiente imagen:
Out:
1
3
5
7
9
Para esto, debemos implementar una instancia de ttk.combobox, y a su vez, indicar los elementos en una lista a través del parámetro values.
lista_desplegable = ttk.Combobox(
values=[
«Lenguajes:»,
«Python»,
«C++»,
«Java»
]
)
lista_desplegable.place(x=10, y=10)
Solo deberíamos agregarle una función para hacer uso de get() y la opción del botón.
Casilla de verificación
También conocida como Checkbox, o Checkbutton, es aquella opción que no permite colocar un tilde para aceptar una condición. Ejemplo de esto puede ser la famosa casilla de “Aceptar términos y condiciones”, fundamental para aplicaciones de escritorio (no solo en Python). Por lo tanto, su función es hacer que el usuario pueda dirimir. En otras palabras, elegir entre si/no, acepto/no acepto, activado/desctivado, etc..
Para realizar esto en aplicaciones de escritorio, vamos a hacer uso de la clase ttk.Checkbutton en Python
checkbutton = ttk.Checkbutton(text=“Aceptar”)
checkbutton.place(x=10, y=10)
Para obtener el estado de nuestra checkbox, será necesario enlazarla con una variable a través de la clase BooleanVar(). Como podemos ver, se trata de un valor bool, es decir, True/False.
bool = tk.BooleanVar()
checkbutton = ttk.Checkbutton(text=“Aceptar”, )
variable=bool)
Una vez realizado esto, vamos a obtener el valor de nuestra casilla (True/False) a través de bool.get() y para establecerlo bool.set().
Agregándole un botón, a modo de ejemplo, quedaría de la siguiente forma:
Por lo tanto, si marco la casilla y presiono el botón, nos devilverá un valor True. En caso contrario, un valor False.
Barras de Progreso
Como en la mayoría de los programas, cuando descargamos o instalamos alguna aplicación se nos suele aparecer un cuadro con una barra de progreso. La misma, nos muestra el proceso, o tiempo, que se ha realizado.
Barra Horizontal
Para hacer uso de ella en Python, usamos la librería ttk.Progressbar:
barraH = ttk.Progressbar(maximum=100)
barraH.place(x=10, y=10, width=100)
Con maximum=100 le indicamos a la barra que, a la hora de cargarse, se pinte el 100% de la misma. Ya que con esto tendríamos más información.
Ahora bien, solo tenemos la forma y tamaño de la barra. Si queremos mostrarla con un porcentaje pintado tendríamos que hacer uso de barra.step(50), cuyo valor refiere al 50% de la barra pintada (la mitad). Si queremos pintar toda la barra tendríamos que colocar barra.step(99.9) ya que, al medirse en forma horaria (o de reloj), el 100 sería igual a 0.
En el caso de querer que la barra se vaya cargando por tiempo, tendríamos que hacer uso de barra.start(50). Con esto la barra se irá cargando cada 50 milisegundos. Esta función es la que suele usarse con descargas, instalaciones, actualizaciones, etc. Solo que el lugar de haber un número, debería haber una variable que las represente. Por ejemplo barra.start(x), donde x=Tiempo_de _descarga
Barra vertical
Por defecto, la barra se presenta de forma horizontal, en caso de quererla representarla de forma vertical haríamos uso de orient=tk.VERTICAL. Por ejemplo:
barra = ttk.Progressbar(orient=tk.VERTICAL, maximum=100)
barra.place(x=10, y=10, height=100)
barra.step(70)
Barra de Menú
La barra de menú son aquellas opciones que se encuentran en la cabecera de nuestra ventana. Haremos uso de la misma a través de la clase tk.Menu, la cual debemos enlazar a la ventana principal.
En el siguiente ejemplo, crearemos dos Menús:
“Archivo” cuya opción será “Nuevo” y retornará un mensaje “Nuevo archivo”.
El otro menú será “Editar” cuya opción será “Copiar” y retornará un mensaje “Archivo copiado”.
Estos menús serán enlazados a la barra con la función add_cascade(). Cada una de las opciones de un menú es añadida a través de add_command(). Veamos el siguiente código:
ventana_pr = tk.Tk()
ventana_pr.title(«Proyecto – Aplicación»)
ventana_pr.config(width=300, height=200)
def nuevo():
print(«Nuevo archivo»)
def copiar():
print(«Copiar archivo»)
barra_menu = tk.Menu()
menu_archivo = tk.Menu(barra_menu, tearoff=0)
menu_archivo.add_command(label=»Nuevo», command=nuevo)
menu_editar = tk.Menu(barra_menu, tearoff=0)
menu_editar.add_command(label=»Copiar», command=copiar)
barra_menu.add_cascade(label=»Archivo», menu=menu_archivo)
barra_menu.add_cascade(label=»Editar», menu=menu_editar)
ventana_pr.config(width=300, height=200, menu=barra_menu)
ventana_pr.mainloop()
Dicho código nos retorna lo siguiente:
Cuadros de diálogo
En distintas aplicaciones de escritorio hecha en Python u otro lenguaje, estos representan un mensaje al usuario cuyo fin es indicar una opción ante una decisión. Por ejemplo, si/no, reintentar/abortar, aceptar/cancelar, etc. Para hacer uso de los mismo, Tk nos provee el módulo tkinter.messagebox.
Por lo tanto, no debemos olvidarnos de importarlo de la siguiente forma:
from tkinter import messagebox
Ahora bien, estos cuadros podemos dividirlos en dos categorías: Los que devuelven valores True/Flase y los que devuelven Ok.
Devolver True/False
messagebox.askokcancel(title=»Pregunta», message=»¿Desea seguir?»)
messagebox.askyesno(title=»Pregunta», message=»¿Desea cancelar?»)
messagebox.askretrycancel(title=»Pregunta», message=»¿Desea reintentar?»)
Devolver Ok
messagebox.showinfo(title=»Info», message=»Se ha descargado el Programa»)
messagebox.showwarning(title=»Advertencia», message=»Los programas de terceros pueden contener virus»)
messagebox.showerror(title=»Error», message=»El siguiente sitio no es seguro.¿Desea seguir?»)
Imágenes
Para colocar imágenes debemos hacer uso del módulo tk.PhotoImage.
imagen = tk.PhotoImage(file=»path/Image»)
Por ejemplo, la siguiente imagen la tenemos en la siguiente ruta:
imagen = tk.PhotoImage(file=»C:/Users/lathack/Desktop/logo.png»)
label = ttk.Label(image=imagen)
label.place(relx=0.5, rely=0.5, relwidth=0.5, relheight=0.5)