Escribiendo aplicaciones para GTK+ con Python y Glade

Esto no esta pensado en convertirse en la “guia definitiva” de Python + Glade. Pero servira como una guia introductoria para empezar a desarrollar aplicaciones graficas multiplataforma.

Bueno, trataremos de llevar este tutorial lo mas practico posible. Tener conocimientos de Python y de GTK es recomendable, pero ninguno es indispensable. Al final del tuto, estan varias URL’s para profundizar mas en cada tema.

Primero vamos a desarrollar la interfaz de nuestra aplicacion, y para eso utilizaremos Glade. Glade es un diseniador de interfaces en esteroides. No solo agiliza el proceso de creacion de widgets y su empaquetamiento, sino que desde el mismo Glade puedes conectar señales para los widgets, definir aceleradores, editar las propiedades de los widgets de una forma grafica, y todo esto viene a guardarse en un bonito XML el cual utilizaremos nosotros desde python… Glade agiliza el proceso de desarrollo CONSIDERABLEMENTE.

Tenemos que definir a nuestro programa, algo sencillo estara bien. Un convertidor de Fahrenheit a Celsius servira.

GLADE

Lo primero que tenemos que hacer, es abrir glade y crear un proyecto nuevo. Cuando nos pregunte que tipo de proyecto queremos realizar, seleccionamos a GTK+

tipo.png

Una vez seleccionado GTK+, la paleta de Glade se habilita y nos muestra los widgets que son soportados por GTK+, entonces procedemos a crear una ventana nueva con el boton de la ventanita (ventanita.png) y dentro de la imagen, creamos una tabla de 2 columnas por 2 renglones con el boton de la tablita (tablita.png) y tu ventana se debe ver algo asi:

ventana.png

Dentro de las 2 celdas de la izquierda, vamos a agregar 2 etiquetas, y esto se hace con el boton con la letra A mayuscula (etiqueta.png). Al lado derecho, agregamos en la celda de arriba una spin button (spin.png) y otra etiqueta abajo. Ahora en el “Widget Tree” seleccionamos la ventana principal y le damos click con el boton derecho y seleccionamos la opcion “Redisplay”. Tu ventana se debe ver algo asi:

redisplay.png

Como pueden ver, se ve bastante mal. Pero todo es cosa de separar un poco los widgets. En este paso vamos a trabajar con el “Widget Tree” y con la ventana de “Properties”. Primero, seleccionamos la ventana principal y en el sus propiedades, modificamos el “Border Width” a 10. Dentro de la tabla, encontraremos las 3 etiquetas y el spin button. Uno por uno, los seleccionamos y en el panel de propiedades, seleccionamos la pestaña de “Packing” y modificamos el “H Padding” y el “V Padding” a 5. Repetimos lo mismo para cada widget dentro de la tabla. Una vez terminado, su ventana debe verse asi:

padding.png

Ahora si vamos a empezar con lo importante de la interfaz. Las dos etiquetas de la izquierda, son las que marcan “Fahrenheit” o “Celsius”. El spin button, es el que el usuario puede modificar para definir los grados fahrenheit. La etiqueta restante (esquina sur-este) Es la que va a mostrar la equivalencia de los grados fahrenheit del spin button en celsius. Esta etiqueta debe ir alineada a la derecha.

Seleccionamos la etiquete superior de la izquierda y en el panel de propiedades, bajo la pestaña de “widget” modificamos la propiedad “Label” y escribimos “Fahrenheit”. Repetimos los mismos pasos para la etiqueta inferior izquierda, pero modificamos el “Label” para que diga “Celsius”.
El spin button requiere un poco mas de cambios. Tomaremos las siguientes consideraciones:

* Solo puede mostrar/recibir numeros
* El incremento/decremento es de una unidad
* El maximo numero posible sera 500
* El minimo numero posible sera -100
* El valor inicial sera 32 (32 grados Fahrenheit equivalen a 0 grados Celsius)

Con estas consideraciones, seleccionamos al spin button del widget tree, y modificamos las siguientes propiedades:

Name            fahr
Numeric         YES
Value           32
Min             -100
Max             500

La etiqueta restante (esquina sur-este) sera la que muestre la equivalencia a Celsius del valor del spin button. Seleccionamos la etiqueta y modificamos las siguientes propiedades:

Name            celsius
Label           0 (Es el valor inicial en grados Celsius)

Por ultimo, necesitamos unos cambios en la ventana principal. Primero el nombre del programa, modificamos la propiedad “Title” y escribimos FtoC o como le quieran llamar a su programa. Tambien tenemos que modificar la propiedad “Rezisable” a NO para que no puedan modificar el tamanio. Esto es porque como tiene muy pocos elementos, si redimensionan la aplicacion se vera muy mal. Una vez terminado todo esto, su aplicacion se debe ver asi:

ftoc.png

Ya casi terminamos con Glade. La programacion visual esta orientada a eventos; un evento es una señal que es emitida por un widget cuando el usuario interactua con el mismo. Con esta teoria, podemos hacernos la pregunta, que evento necesitamos interceptar nosotros?
Nuestro programa va a mostrar los grados Celsius a partir de los grados Fahrenheit, pero cuando va a cambiar la temperatura??? Cuando el usuario modifique el valor del spin button. Entonces, necesitamos interceptar el evento del cambio de valor del spin button. Esto se hace seleccionando el widget del widget tree, y en el panel de propiedades, en la pestaña de “Signals” seleccionamos la señal que nos interesa presionando el boton con los 3 puntos de la propiedad Signal (IMAGEN). Al presionar este boton, nos muestra una lista de todas las señales que puede emitir este widget. En la categoria de “GtkSpinButton Signals” seleccionamos “value_changed” y presionamos OK. Esto nos crea un handler que se llama (si siguieron las indicaciones del documento) “on_fahr_value_changed” y lo aniadimos a la lista de señales presionando el boton “Add”. Deberia quedarles algo asi:

signal.png

Vamos a agregar una ultima señal, al widget de la ventana principal. Repetimos los mismos pasos anteriores, pero ahora la señal que seleccionaremos es “destroy” que pertenece a la categoria de “GtkObject signals”. El holder debe de llamarse “on_window1_destroy”, lo agregamos y ya terminamos con Glade.

PYTHON

Ahora empezamos con la programacion. Lo que vamos a hacer es ver el codigo fuente completo, y despues, iremos comentando que hace cada parte, asi que sin mayor preambulo:


import gtk
from gtk import glade

class FtoC:
   def __init__(self):
      self.xml = glade.XML("ftoc.glade", None, None)
      self.xml.signal_connect("on_fahr_value_changed",  \\
self.on_spin_change)
      self.xml.signal_connect("on_window1_destroy",  \\
lambda w: gtk.main_quit())
      self.spin = self.xml.get_widget("fahr")
      self.result = self.xml.get_widget("celsius")

   def on_spin_change(self, w):
      fahr = self.spin.get_value_as_int();
      cent = (fahr - 32) / 1.8
      texto = "%.2f C" % cent
      self.result.set_label(texto)

 if __name__ == "__main__":
   ftoc = FtoC()
   gtk.main()

Este codigo puede tener cualquier nombre, pero tiene que estar guardado en el mismo directorio que el archivo de Glade.

Vamos a irlo analizando por partes:

import gtk
from gtk import glade

importamos los modulos de gtk y glade. El modulo de gtk es que que permite manejar a todos los widgets. El modulo glade permite convertir el XML creado en glade a los objetos que utiliza GTK.

class FtoC:

definimos la clase. No tengo que dar muchas explicaciones aqui…

    def __init__(self):

Aqui definimos el constructor de la clase y es donde sucede toda la magia.

         self.xml = glade.XML("ftoc.glade", None, None)

Guardamos el objeto del tipo glade.XML en self.xml para poder accesarlo mas tarde

self.xml.signal_connect("on_fahr_value_changed", \\
self.on_spin_change)
self.xml.signal_connect("on_window1_destroy", \\
lambda w: gtk.main_quit())

Se acuerdan de las señales que habiamos definido?? Bueno, ahora las vamos a conectar a sus handlers. Los handlers son funciones que son llamadas automaticamente cuando se detecte un evento en especifico. En este caso, cuando detectamos la señal “on_fahr_value_changed” vamos a llamar al metodo de la clase llamado “on_spin_change”. Cuando se detecte la señal “on_window1_destroy” vamos a ejecutar la funcion lambda w, que va a destruir nuestra aplicacion, es decir, se va a terminar su ejecucion. Esta señal es activada cuando el usuario presiona Alt+F4 o hace click en la X de la aplicacion.

self.spin = self.xml.get_widget("fahr")
self.result = self.xml.get_widget("celsius")

el metodo “get_widget” es el que convierte la informacion del glade XML a un objeto GTK. Esta funcion es muy sorprendente, porque busca en el XML de glade, el widget que le pasamos como parametro, encuentra su tipo y todas sus propiedades. Magicamente crea el objeto de GTK dependiendo de los valores encontrados en el XML y regresa una referencia al objeto. En palabras mas simples, self.spin y self.result son objetos del tipo Gtk Spin Button y Gtk Label, y tienen todos sus metodos y propiedades.

     def on_spin_change(self, w):

Aqui definimos el handler de la señal “on_fahr_value_changed”. Todos los handlers en PyGTK reciben al menos 1 parametro, el cual es una referencia al widget que los mando llamar, por eso definimos el argumento “w”.

         fahr = self.spin.get_value_as_int();
cent = (fahr - 32) / 1.8
texto = "%.2f C" % cent
self.result.set_label(texto)

Estas cuatro lineas se explican por si mismas. Cuando cambia el valor del spin button, primero obtenemos el valor que hay en el widget, el cual se obtiene con get_value_as_int() que es un metodo de los objetos tipo Gtk Spin Button. En la siguiente linea, hacemos la conversion a los grados Celsius. En la tercer linea, redondeamos los grados Celsius a 2 decimales, le agregamos el caracter “C” al final de los grados y en la ultima linea la desplegamos con el metodo set_label() que es un metodo de los objetos tipo Gtk Label.

Porque 4 lineas??? porque es mas sencillo de explicar que esto:

         self.result.set_label("%.2f C" % \\
((self.spin.get_value_as_int() - 32) / 1.8))

Y por ultimo:

 if __name__ == "__main__":
     ftoc = FtoC()
     gtk.main()

En proyectos grandes, es necesario tener modulos (clases) en archivos separados. Si el archivo que estamos ejecutando es __main__ (no esta siendo importado) entonces, creamos un objeto de la clase que acabamos de definir y llamamos a gtk.main(). gtk.main() es el metodo que inicia la aplicacion grafica y la despliega.

final.png

Su programa convertidor de grados Fahrenheit a Celsius esta completo y funcional. Espero que esta guia introductoria les sirva como base para entender la programacion de Python + Glade. Aqui les dejo el archivo fuente de python y glade. Suerte y Happy Hacking!

Referencias