En el tutorial de Organización de widgets en wxPython, habíamos usado el IDE wxFormBuilder para crear distintos ejemplos, e incluso algunas interfaces completas. Como les dije al final de dicho tutorial, la idea es que esos proyectos que creamos, realmente podamos usarlos en una aplicación concreta, y poco a poco, “darles vida”.
En esta primera parte, vengo a (empezar a) cumplir con lo prometido, y les explicare como exportar las interfaces que creamos con wxFormBuilder, y luego cargarlas en nuestra aplicación Python.
Exportar la interface desde wxFormBuilder
wxPython nos permite cargar la interface de nuestra aplicación, desde un archivo de recursos (XRC), de modo que podamos aislar la lógica de la aplicación, de su interface visual. Un archivo de recursos, no es mas que un archivo XML que contiene toda la información sobre los elementos que conforman la interface. Si bien no vamos entrar en detalle sobre el contenido del archivo, a continuación te muestro una pequeño archivo, para que veas que realmente no hay nada mágico dentro él, y que leyéndolo con atención, es fácilmente entendible:<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<resource xmlns="http://www.wxwindows.org/wxxrc" version="2.3.0.1">
<object class="wxFrame" name="MyFrame">
<style>wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL</style>
<title>Ventana de ejemplo</title>
<object class="wxBoxSizer">
<orient>wxVERTICAL</orient>
<object class="sizeritem">
<option>0</option>
<flag>wxALL|wxEXPAND</flag>
<border>5</border>
<object class="wxButton"name="m_button1">
<label>Aceptar</label>
<default>0</default>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<flag>wxALL|wxEXPAND</flag>
<border>5</border>
<object class="wxButton" name="m_button2">
<label>Cancelar</label>
<default>0</default>
</object>
</object>
</object>
</object>
</resource>
Este archivo corresponde a la siguiente interface gráfica:

Al trabajar con wxFormBuilder, cuando guardamos nuestro trabajo, veremos que el archivo que se guarda lleva la extensión .fbp (Form Builder Proyect), y no XRC (XML resource), esto es así porque wxFormBuilder esta guardando cierta información del proyecto que solo le sirve a el mismo, pero nosotros necesitamos exportar la interface de modo que sólo nos quede un archivo XRC válido para que lo pueda manipular wxPython.
Desde wxFormBuilder, podemos ver en todo momento como esta quedando el archivo XRC; para lo cual simplemente debemos pasar a la solapa “XRC” que se encuentra en la parte inferior del Editor.

Como habrás visto, además de la vista "Designer" y "XRC", existe también la vista C++, donde podremos ver el código necesario para obtener la interface en lenguaje C++. Las tres vistas (“Desginer”, “C++” y “XRC”) están sincronizadas en todo momento, e incluso puedes estar en cualquiera de ellas, y seguir construyendo la interface (agregar Sizers, botones, etc.) y ver como va quedando en C++ o XRC. Si bien las vistas "C++" y "XRC" son sólo texto, no podemos editar su contendido en forma manual.
Para obtener nuestro archivo XRC, tenemos dos caminos:
1- El primer camino, se trata de entrar en la solapa "XRC", copiar todo el código, pegarlo en un editor de texto, y guardarlo.
2- El segundo camino consiste en que el propio wxFormBuilder guarde el archivo XRC. Para que wxFormBuilder guarde el XRC en un archivo externo al del proyecto (.fbp), debemos elegir el proyecto en el “Object Tree”, y dentro de las propiedades de éste, expandimos la propiedad code_generation, y activamos la opción XRC; incluso podemos quitar la opción C++ (la única activada por defecto) dado que no estamos usando este lenguaje. Además de decirle que crée el archivo XRC, podemos especificar como queremos que se llame y donde queremos que lo guarde. Por defecto el archivo se llamará “noname.xrc”, pero si cambiamos el valor de la propiedad file, éste será el nombre del archivo generado. Para especificar donde queremos que se guarde el archivo, lo hacemos en la propiedad path, la cual por defecto sera el directorio donde esta guardado el proyecto (.fbp), es por esto que el valor inicial que aparece en la propiedad es un punto (.), el cual representa el directorio actual.
El primer camino que vimos funciona correctemente, pero no es la opción mas práctica, dado que cada vez que modificamos algo en la interface, debemos repetir todos los pasos (copiar el código, pegarlo en otro archivo y guardarlo), es por esto que es recomendable usar siempre la segunda opción.

Configurando estas opciones, ya sólo nos resta ir al menú “File” y elegir “Generate code” (o bien pulsar F8). Luego de realizar esto, tendremos el archivo XRC listo para usar en el directorio que especificamos en la propiedad path.
Ahora que tenemos el archivo de recursos, pasaremos a ver cómo lo usamos en nuestra aplicación.
Usar el archivo XRC con wxPython
En esta parte, veremos paso a paso como cargar y empezar a utilizar el archivo XRC con wxPython.1- Importar la librería "wx"
Antes de poder comenzar cualquier aplicación que utilice wxPython, debemos importar la librería “wx”.import wx
2- Crear el objeto “Aplicación”
Sin entrar en detalle, debemos tener claro que todo programa que utilice wxPython, necesita de dos objetos fundamentales: el objeto “aplicación” y el objeto “ventana de nivel superior”.El objeto “aplicación” es una instancia de la clase wx.App (o una subclase de ésta). La principal función de este objeto, es la de recoger los eventos que se vayan generando y “enlazarlos” con su correspondiente manejador de evento.
El objeto “ventana de nivel superior” es un widget que no esta contenido dentro de otro. En la aplicación debe haber al menos una ventana de nivel superior, y de hecho, si se cerraran todas las ventanas de nivel superior, el programa terminaría. En general, este objeto será una subclase de wx.Frame o wx.Dialog.
Para crear el objeto “aplicación” como una instancia de la clase wx.App, simplemente escribiremos lo siguiente:
LaAplicacion = wx.App()
Este enfoque es útil, sólo cuando nuestra aplicación sa muy sencilla y posea una única ventana (luego volvere sobre este tema), pero en general, lo aconsejado es crear una subclase de wx.App como pueden ver a continuación:
class MiAplicacion (wx.App):
....
....
....
if __name__ == '__main__':
LaAplicacion = MiAplicacion()
Al crear la subclase de wx.App, podemos utilizar el método OnInit() como lugar para generar todo lo que necesitemos referido a la GUI de la aplicación. En nuestro caso, cargaremos el archivo de recurso (XRC).
3- Cargar el archivo XRC
Para cargar el archivo de recursos (XRC), usaremos la clase XmlResource. Veamos un ejemploself.res = xrc.XmlResource('gui_tutorial.xrc')
Aquí estamos creando un objeto llamado self.res, que es de la clase XmlResource. Al crear el objeto, le pasamos como parámetro, el nombre del archivo que contiene nuestra interface. Luego de hacer esto, ya tendremos almacenado el archivo XRC en el objeto self.res.
IMPORTANTE:
Para que la linea de código anterior funcione, debemos importar explícitamente el módulo “xrc” desde “wx”:
from wx import xrc
de no importar este módulo, deberíamos escribir lo siguiente (pero no se suele usar):
wx.xrc.XmlResource
Como dijimos antes, la idea es cargar el archivo de recurso dentro del método OnInit() en la subclase de wx.App. Combinando todo lo dicho hasta el momento, el código quedaría así:
import wx
from wx import xrc
class MiAplicacion(wx.App):
def OnInit(self):
self.res = xrc.XmlResource('gui_tutorial.xrc')
...
...
...
if __name__ == '__main__':
LaAplicacion = MiAplicacion()
En este punto, todavía no podemos ejecutar nuestra aplicación, ya que aún no especificamos la ventana de nivel superior (entre otras cosas).
4- Especificar la “Ventana de nivel superior”
Como les había dicho antes, además del objeto “Aplicación”, el otro objeto indispensable en toda aplicación que haga uso de wxPython, es la "ventana de nivel superior". En nuestro ejemplo, la ventana de nivel superior, es el Frame llamado “MyFrame”, por lo que para cargarlo haríamos lo siguiente:self.frame = self.res.LoadFrame(None, 'MyFrame')
Luego de esta línea, en el objeto self.frame tendríamos cargado el Frame “MyFrame” listo para usar. Como ven, el Frame lo estamos cargando desde self.res, que es donde teníamos cargado el archivo XRC. El primer parámetro indica que el Frame no depende de nadie (None). El segundo parámetro, es el nombre del Frame que queremos cargar. Como en este caso sólo tenemos un único Frame, wxPython asumirá que es la ventana de nivel superior, de lo contrario, podríamos utilizar el método SetTopWindow() de la clase wx.App.
Al cargar el Frame, éste no será visible, a menos que invoquemos su método show().
self.frame.Show()
Si juntamos todo lo visto hasta ahora, el código sería el siguiente:
import wx
from wx import xrc
class MiAplicacion(wx.App):
def OnInit(self):
self.res = xrc.XmlResource('gui_tutorial.xrc')
self.frame = self.res.LoadFrame(None, 'MyFrame')
self.frame.Show()
return True
if __name__ == '__main__':
LaAplicacion = MiAplicacion()
Para que este ejemplo se pueda ejecutar, debemos iniciar el bucle de eventos; con lo cual le estaremos indicando a wxPython, que se quede a la escucha de eventos (pulsaciones de teclas, clicks, etc.).
Comenzar a escuchar eventos
Para iniciar el bucle de eventos, usamos el método MainLoop() de la clase wx.App (En nuestro caso, lo hacemos sobre nuestra clase LaAplicacion que es una sublcase de wx.App).LaAplicacion.MainLoop()
El código completo, quedaría así.
import wx
from wx import xrc
class MiAplicacion(wx.App):
def OnInit(self):
self.res = xrc.XmlResource('gui_tutorial.xrc')
self.frame = self.res.LoadFrame(None, 'MyFrame')
self.frame.Show()
return True
if __name__ == '__main__':
LaAplicacion = MiAplicacion()
LaAplicacion.MainLoop()
Al ejecutar este ejemplo, obtendremos la ventana tal como la creamos con wxFormBuilder, pero ahora es “real”. Podrás clickear los botones, redimensionar la ventana, minimizarla, maximizarla, etc., aunque claro esta, aún no hace nada interesante.

Por ahora dejaremos aquí, y en la siguiente parte de este tutorial, veremos como hacer que la ventana “haga algo”. También te mostraré como hacer este mismo ejemplo, pero sin generar la subclase de wx.App, y por último, veremos como hacer un pequeño cambio en el método OnInit() para mejorar la claridad del mismo.
Nos vemos en la segunda parte!
Editado:
Ya esta disponible la parte II
9 comments
Seria bueno que identes las lineas, para simplificar en la ejecucion del ejemplo. Buen tuto, saludos.-
import wx
from wx import xrc
class MiAplicacion(wx.App):
_def OnInit(self):
__self.res = xrc.XmlResource('dynamic2.xrc')
__self.frame = self.res.LoadFrame(None, 'MyFrame1')
__self.frame.Show()
__return True
if __name__ == '__main__':
_LaAplicacion = MiAplicacion()
_LaAplicacion.MainLoop()
Hola Alvaro, me alegra que te haya gustado el tutorial. Gracias por hacerme notar que la identación del código se perdió (creeme que estaba!!) El tema es que al editar el articulo (luego de ya haberlo guardado) Blogger elimina los tabuladores. En breve lo estaré solucionando.
Un saludo!
Gracias Pablo me funciono de maravilla me falta es leer la parte que relaciona la interfase y el programa como tal
Hector
Excelente tutorial, de verdad te felicito Pablo, tienes muy buena pedagogía!!!!
Saldos
Gracias a ustedes por seguir mis tutoriales. Joger no se si es tan buena mi pedagogía, pero si te aseguro que intento ser lo mas claro posible. Cualquier duda, no tienen mas que consultar.
Saludos!
Gracias Pablo he estado leyendo y aprendiendo mucho de tus tutoriales, eres excelente explicando las cosas, Se te agradece Muchísimo.
Exelente!!! muy buen tutorial !!!
Hola!. Muchas gracias por los tutoriales, me ayudaron mucho!!!. En la versión 3.1 está incluida la ficha para generar código en Python. Seria muy bueno que hagas un tutorial de como usarlo... Gracias una vez mas.
Publicar un comentario