Si has llegado aquí mediante un buscador o por simple casualidad, te cuento que estas en la tercera parte de un tutorial que empieza AQUI.
En esta ultima entrega del tutorial, agregaremos un menú a la interface de ejemplo que venimos usando, y luego veremos como detectar los eventos del menú para reaccionar en consecuencia. Como lo venimos haciendo hasta ahora, seguiremos haciendo uso de wxFormBuilder.
Agregando un menú a nuestra interface con wxFormBuilder
En primer lugar, abriremos el proyecto que contiene la interface (archivo .fbp). De no tener el archivo del proyecto, pero si contar con el archivo .xrc, wxFormBuilder nos da la opción de importarlo; para lo cual creamos un proyecto vacío y seleccionamos la opción "Import XRC..." del menú "File". El Object Tree se vería así:
Para agregar el menú con wxFormBuilder, tenemos dos alternativas:
Opción 1: "Manual"
La primera opción, es la alternativa "más manual” de las dos.Un menú esta compuesto por una barra de menú (wx.MenuBar), que contiene los distintos menues propiamente dichos (wx.Menu), como ser "Archivo", "Editar", "Ver", etc., y dentro de estos, existen uno o mas ítems de menú (wx.MenuItem), como ser "Abrir", "Cerrar", "Imprimir", etc.; también pueden existir submenues, que en realidad no son mas que menues (wx.Menu) dentro de otro menú. Dicho esto, pasaremos a crearlo.
El menú que vamos a crear es muy sencillo. Para que veas las opciones que tendrá, a continuación te muestro una imagen:


Tras agregar la barra de menú, el Editor se vería así:

Como segundo paso, vamos a agregar a la barra de menú, el menú "Opciones". Para agregarlo tan solo debemos clickear el botón wx.Menu en la misma solapa desde la que agregamos la barra. Una vez agregado, editamos su propiedad label con el texto "Opciones".

Por último, agregamos dos ítems pulsando dos veces el botón wxMenuItem en la barra de componentes, y modificamos la propiedad label de ambos, el primero con el valor "Mostrar bienvenida" y el segundo con el valor "Salir".

Con esto tendríamos nuestro menú terminado. El Object Tree se ve así:

Si ejecutamos la ventana pulsando F5, veremos lo siguiente:


Si ahora ejecutamos la ventana, la veríamos correctamente:


La solución de mover el menú a la parte superior dentro del Object Tree, por ahora te pido que lo tomes "tal cual te lo digo", en otra oportunidad cuando haga un tutorial especifico sobre menues en wxPython, hablaremos mas en detalle.
Opción 2: "Asistida"
En este método, usaremos una herramienta de wxFormBuilder, que nos permite editar el menú en forma mas asistida. Para invocarla, pulsamos el botón derecho del mouse sobre el Frame en el Object Tree y elegimos la opción Menu Editor...
El editor de menú lo puedes ver en la siguiente imagen:

Veamos paso a paso como crear el mismo menú que antes, pero ahora usando el Editor de menú:
A diferencia del método anterior, aquí no tenemos que agregar la barra que contendrá el menú (wx.MenuBar), ya que el asistente lo hará por nosotros, así que simplemente empezamos agregando el menú "Opciones" (wx.Menu). Para agregar este menú, tan solo debemos escribir el nombre del mismo (en este caso “Opciones” ) en la caja de texto junto a la etiqueta "label" y pulsar el botón "Add":

Tras pulsar el botón "Add", veremos que en el panel de la izquierda del Menu Editor se agregara una fila que representa el nuevo menú:

Al escribir el valor de la propiedad "label", el asistente completará las propiedades "Id" y "Name" automáticamente, pero de todos modos, podemos editarlos en forma manual.
Ahora repetimos el procedimiento anterior, pera con el texto "Mostrar bienvenida" en la propiedad label. Una vez agregado este item de menú, la lista del panel izquierdo del Menu Editor quedara así:

Si bien el ítem ha sido agregado, aun no hemos indicado que este ultimo es un wx.MenuItem; para que wxFomBuilder lo reconozca como tal, pulsamos el botón que tiene el signo mayor (>).

Al pulsar el botón “>”, el ítem que tengamos seleccionado se convierte en el hijo del ítem que tiene en la fila que se encuentre arriba de el.
Ya sólo nos queda agregar el otro ítem de menú (“Salir”), así que procedemos a repetir los mismo pasos que hicimos para agregar el ítem de menú “Mostrar Bienvenida”, pero ahora con el label "Salir". Luego de agregarlo, el Menu Editor quedaría así:

Listo, de este modo tenemos el menu terminado haciendo uso del Editor de Menú de wxFormBuilder. Una vez mas, no quise entrar en detalle sobre las características de este Editor, ya que eso lo veremos en otro tutorial más especifico sobre el uso de Menues.
En mi caso, para agregar el menú, opte por la opción asistida. Ya sea que usemos el meo todo 1 (“Manual”) o el método 2 (”Asistido”), debemos exportar el archivo XRC como ya vimos antes, y luego pasamos nuevamente al código de nuestra aplicación, para darle uso a nuestras dos opciones de menú.
Manejando los eventos de nuestro menú
Para refrescar la memoria, a continuación te muestro el código de nuestra aplicación hasta el momento:import wxEn primer lugar, enlazaremos el ítem de menú "Mostrar bienvenida" con el mismo manejador de evento que teníamos creado para el botón "Aceptar". Esto de enlazar un mismo manejador de evento con varios widgets es muy común, sobre todo lo podemos ver en el caso que una misma función, la ejecutamos desde una opción de menú y desde un botón de una barra de herramientas (Por ej: las opciones Cortar, Copiar, Pegar, en general la encontramos como items del menú Editar y como botones de una barra de herramientas).
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.botonAceptar = xrc.XRCCTRL(self.frame, 'm_button1')
self.frame.Bind(wx.EVT_BUTTON, self.mostrar_bienvenida, self.botonAceptar)
self.botonCancelar = xrc.XRCCTRL(self.frame, 'm_button2')
self.frame.Bind(wx.EVT_BUTTON, self.salir, self.botonCancelar)
self.frame.Show()
return True
def mostrar_bienvenida(self, event):
wx.MessageBox('Bienvenido!')
def salir(self, event):
self.frame.Close()
if __name__ == '__main__':
app = MiAplicacion()
app.MainLoop()
Para hacer el enlace haremos uso (nuevamente) de la la función Bind(). Hasta el momento hemos usado la función xrc.XRCCTRL() para obtener una referencia al widget del que queremos captar el evento, pero esto no nos servirá para el caso de los menues. La función xrc.XRCCTRL() sólo puede retornar objetos que deriven de la clase wxWindow, pero cuando esto no se cumple, como es el caso de la clase wxMenuItem, deberemos hacer uso de la función xrc.XRCID(), la cual nos devuelve el ID del widget que tenga el nombre que le pasamos como parámetro y luego usar este ID en el parámetro id de la función Bind(). El código para enlazar el ítem de menú "Mostrar bienvenida" con la función mostrar_bienvenida() será el siguiente:
self.frame.Bind(wx.EVT_MENU, self.mostrar_bienvenida, id=xrc.XRCID('mostrarBienvenida'))
Teniendo en cuenta esto, sólo me queda comentarte que el Event Binder para capturar la pulsación de un ítem de menú es wx.EVT_MENU, es por esto que el valor del primer parámetro es justamente este.
Para enlazar el segundo ítem de menú ("Salir") el código sería el siguiente:
self.frame.Bind(wx.EVT_MENU, self.salir, id=xrc.XRCID('salir'))
Si ahora juntamos todo el código, nos 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.botonAceptar = xrc.XRCCTRL(self.frame, 'm_button1')
self.frame.Bind(wx.EVT_BUTTON, self.mostrar_bienvenida, self.botonAceptar)
self.botonCancelar = xrc.XRCCTRL(self.frame, 'm_button2')
self.frame.Bind(wx.EVT_BUTTON, self.salir, self.botonCancelar)
self.frame.Bind(wx.EVT_MENU, self.mostrar_bienvenida, id=xrc.XRCID('mostrarBienvenida'))
self.frame.Bind(wx.EVT_MENU, self.salir, id=xrc.XRCID('salir'))
self.frame.Show()
return True
def mostrar_bienvenida(self, event):
wx.MessageBox('Bienvenido!')
def salir(self, event):
self.frame.Close()
if __name__ == '__main__':
app = MiAplicacion()
app.MainLoop()
Si ejecutamos el programa, ahora podemos pulsar el botón "Aceptar" o seleccionar la opción "Mostrar bienvenida" del menú "Opciones", y obtendremos el mensaje "Bienvenido!"; y si pulsamos el botón "Cancelar" o elegimos la opción "Salir" del menú "Opciones", el programa finalizará.
Con esto doy por terminado este tutorial. Como siempre, apelo a ustedes para que si consideran necesario agregar, modificar, eliminar y/o corregir algo, lo comenten así entre todos vamos generando cada vez mas material en nuestro idioma sobre wxPython.
Saludos!
9 comments
querido pablo, me gusto mucho el tuto, por la claridad y facilidd con que encaras los ejemplos... Te segui desde el primero, pero tengo un inconveniente grande pues pa version de wxpython todavia es inestable lo que genera que se cierre el programa en pleno trabajo de diseño. Podrias decirme que version tengo que manejar o que cuidados debo considerar a la hora de trabajar.
Te agradecere mucho puedas orientarme y asi seguir adelante, investigando y por supuesto siguiendo el material que publicas.
Saludos Anita Garcia de Bolivia
Hola Anita, ante todo gracias por seguir mis artículos. En cuanto a lo que me preguntas sobre wxFormBuilder es real que por momentos es bastante inestable. La ultima versión "estable" al día de hoy (14/06/09) es la 3.0.57 y hace unos días salio la beta de la versión 3.01.61, que permite generar código en Python (wxPython), la cual era una característica bastante esperada por muchos (me incluyo), pero aun no la probé. Realmente, el único consejo que te puedo dar, es: guardar, guardar y guardar!! mientras esperamos que con cada versión este excelente programa mejore aun mas. También te recomiendo que pruebes XRCed o wxGlade. Mi elección por wxFormBuilder a la hora de escribir estos tutoriales es porque me parece el mas simple e intuitivo y hace mas fácil aprender el tema, pero una vez que tienes los conocimientos básicos, puedes probar cualquiera de los IDEs disponibles. En algún momento estaré escribiendo un articulo sobre como utilizar XRCed ya que es muy simple pero poderoso al mismo tiempo.
Espero que te animes a probar alguno de los IDEs que te nombre y si no recuerda GUARDAR cada vez que des un paso importante en wxFormBuilder.
Saludos desde Argentina!
Disculpa Pablo, pero tengo un problema con los eventos de cuatro textctrl y un boton; lo que quiero hacer es intorucir un valor en los 3 primeros, y que al presionar el boton, en el utimo textctrl aparesca un resultado; e buscado en google y en todos lados y no encuentro nada...
Hola "Anónimo", suponiendo que tienes guardada la interfaz en un archivo llamado "gui.xrc", a continuación te muestro un pequeño ejemplo de una posible implementación:
import wx
from wx import xrc
class appEjemplo(wx.App):
def OnInit(self):
self.res = xrc.XmlResource('gui.xrc')
self.frame = self.res.LoadFrame(None, 'MyFrame1')
self.frame.Bind(wx.EVT_BUTTON, self.onSumar, xrc.XRCCTRL(self.frame, 'm_button1'))
self.frame.Show()
return True
def onSumar(self, evt):
val1 = int(xrc.XRCCTRL(self.frame, 'm_textCtrl1').GetValue())
val2 = int(xrc.XRCCTRL(self.frame, 'm_textCtrl2').GetValue())
val3 = int(xrc.XRCCTRL(self.frame, 'm_textCtrl3').GetValue())
textboxResultado = xrc.XRCCTRL(self.frame, 'm_textCtrl4')
textboxResultado.SetValue(str(val1 + val2 + val3))
app = appEjemplo()
app.MainLoop()
Espero que este ejemplo te sirva de base para lo que quieres hacer, sino te pido que me des alguna precisión mas para poder orientarte mejor.
Saludos,
Pablo Tilli.
Muchas Gracias por el tutorial, esta super. Que me recomiendas para empaquetar una aplicacion (especie paquete instalador)
Saludos desde Colombia
Jose Arley
muy buen post bro..
lastima que creo que odio a los sizers..
nada a la visual basic? drag & drop?
muy buen tutorialijillo
Se que los Sizers parecen dificiles de comprender al principio, pero con practica se los puede dominar con fluidez y aprovechar sus ventajas. Si te surge alguna duda con una interface en particular no tienes mas que preguntar. Si usas alguna distro de Linux, y quieres algo al estilo del IDE de Visual Basic puedes probar GAMBAS2, que aunque no tiene nada que ver con Python y solo sirve para crear aplicaciones Linux, te puede ser util mientras sigues practicando y descubriendo lo bueno de otras fomar de trabajar con interfaces graficas.
Hasta la proxima,
Pablo Tilli.
Hola tenes idea de como hacer que el LoadFrame reconozca objeto personalizados ? es decir, tengo una clase ("MiBoton") que extiende el objeto Button, pero al cargar el frame me dice "No handler found for XML node 'object', Class 'MiBoton'!"
skiros@hotmail.com
super!!!! muy bueno...
Publicar un comentario