Si has llegado aquí mediante un buscador o por simple casualidad, te cuento que estas en la quinta parte de un tutorial que empieza AQUI.
En esta entrega comenzaremos a dotar a nuestro Catálogo de una mayor “usabilidad”; concretamente vamos a implementar la posibilidad de que al estar modificando una película en el Editor, se nos permita navegar hacia la primera, última, anterior y siguiente película (a través de una típica barra de navegación con cuatro botones), sin necesidad de cerrar la ventana de edición para modificar otra película. Para hacerlo mas flexible aún, además de la barra de navegación en el Editor de películas, permitiremos que cuando el usuario esté en la ventana de edición, pueda seleccionar directamente cualquier película en la Vista Principal, y que ésta se cargue automáticamente en el Editor sin necesidad de cerrarlo.
Modificando la interface del Editor de películas con wxFormBuilder
Lo primero que haremos antes de avanzar con el código, sera modificar nuestro archivo XRC (gui.xrc), para agregar la barra de navegación que les mencione antes. A continuación les muestro una captura de pantalla del Editor y una del Árbol de objetos de wxFormBuilder, con el Dialogo del Editor de Películas modificado:
Viendo el Árbol de objetos, podemos notar que la barra de navegación, consta de cuatro botones (wxBitmapButton) contenidos en dos BoxSizer (Horizontales), que a su vez se encuentran contenidos en un GridSizer, que esta dentro de un Panel. El GridSizer tiene una sola fila y dos columnas (rows=1, cols=2). El boxSizer bSizer41 (el que contiene los botones “Primero” y “Anterior”) posee la flag wxExpand activada. El boxSizer bSizer5 (el que contiene los botones “Ultimo” y “Siguiente”) posee la flag wxALIGN_RIGTH activada y la flag wxExpand desactivada. El Panel posee la flag wxExpand activada, la propiedad proportion en “1” y tiene un borde de 3px a cada uno de sus lados. Para poner las imágenes en los botones, simplemente seleccionamos la ruta al archivo en el file_path de la propiedad bitmap de los wxBitmapButton.
Claramente los nombres de los distintos widgets no son los ideales, así que les dejo de tarea a ustedes, ponerles nombres mas representativos.
Con esto, ya estamos en condiciones de seguir trabajando con el código.
Agregando funcionalidad
Ahora que ya tenemos nuestra barra de navegación en la interface del Editor de Películas, podemos comenzar a trabajar para que esta cumpla su función, pero antes de meternos de lleno con esta tarea, vamos a implementar la función que nos permitirá que al estar abierto el Editor de películas, podamos seleccionar otra película en la Vista Principal y ésta se cargue en el Editor.
Para implementar esta característica, empezaremos por agregar un método llamado onSeCambioItemSeleccionado() en el Controlador del Editor de Películas. Básicamente, este método se encargará de "tramitar" la llamada para cargar la información de la película que esté seleccionada en la Vista Principal, dentro del Editor; porque si bien ya tenemos el método cargarPelicula() en la Vista del Editor de Película, éste necesita que le enviemos el ID de la película a cargar, es por esto, que debemos averiguarlo antes de invocarlo. Para esto, también vamos a agregar el método cargarPeliculaSeleccionadaEnVistaPrincipal(), que obtendrá el ID y se lo pasara como parámetro al método cargarPelicula() de la Vista Principal.
def onSeCambioItemSeleccionado(self, evt):También modificaremos el método __init__() del Controlador del Editor de Peliculas:
self.cargarPeliculaSeleccionadaEnVistaPrincipal()
def cargarPeliculaSeleccionadaEnVistaPrincipal(self):
self.idPelicula = self.app.controladorVistaPrincipal.vista.getIDItemSeleccionado()
self.vista.cargarPelicula(self.idPelicula)
def __init__(self, app, parent, agregar=True):El motivo de este cambio, es que antes sólo cargábamos la información de la película al abrir el Editor, entonces el código encargado de esta tarea tenia sentido que este en el método __init__(), pero como ahora esta tarea se puede dar incluso cuando el Editor esta abierto, recurrimos a este nuevo esquema.
self.app = app
self.vistaPrincipal = parent
self.vista = VistaEditorDePelicula(self.vistaPrincipal.frame, self.app, agregar)
btnAgregarPelicula = xrc.XRCCTRL(self.vista.Dialog, 'btnAceptar')
if(agregar):
self.vista.Dialog.Bind(wx.EVT_BUTTON, self.onAgregarPelicula, btnAgregarPelicula)
else:
self.vista.Dialog.Bind(wx.EVT_BUTTON, self.onModificarPelicula, btnAgregarPelicula)
self.cargarPeliculaSeleccionadaEnVistaPrincipal()
self.vista.Mostrar()
Si bien hemos agregado el método onSeCambioItemSeleccionado(), aun nos falta que este sea invocado cuando efectivamente el usuario selecciona una película en la Vista Principal y tiene el Editor de Películas abierto.
Para lograr esto, vamos a recurrir nuevamente a la clase Publisher del modulo wx.lib.pusub, empezando por hacer las siguientes modificaciones en el controlador de la Vista Principal.
1- Importamos la clase Publisher
from wx.lib.pubsub import Publisher
2- Dentro del método __init__(), comenzamos la “escucha” del evento que nos indica que se selecciono un ítem en la lista de películas.
listadoPeliculas = xrc.XRCCTRL(self.vista.frame, 'listPeliculas')
self.vista.frame.Bind(wx.EVT_LIST_ITEM_SELECTED, self.onSeCambioItemSeleccionado, listadoPeliculas)
3- Creamos un manejador para este evento, para que se encargue de “comunicar” que la selección de la película en la Vista Principal ha cambiado.
def onSeCambioItemSeleccionado(self, evt):
Publisher.sendMessage('cambio_item_seleccionado', None)
Ahora haremos que el Controlador del Editor se quede a la escucha del mensaje 'cambio_item_seleccionado'. Los cambios necesarios serian los siguientes:
1- Importamos la clase Publisher
from wx.lib.pubsub import Publisher
2- Dentro del método __init__(), comenzamos la "escucha" del mensaje 'cambio_item_seleccionado':
Publisher.subscribe(self.onSeCambioItemSeleccionado, 'cambio_item_seleccionado')
Como se puede ver, al “escuchar” el mensaje 'cambio_item_seleccionado' se llama al método onSeCambioItemSeleccionado(), con lo cual lograremos nuestro objetivo de que la información de la película seleccionada en la Vista Principal se cargue en el Editor cuando esta abierto.
Por ultimo, para que el Editor sea mostrado (en modo “Agregar” o “Editar”), modificaremos los métodos onMostrarAgregarPelicula() y onMostrarEditorDePelicula() en el controlador de la Vista Principal.
def onMostrarAgregarPelicula(self, evt):Ahora sí estamos en condiciones de hacer que nuestra barra de navegación funcione.
self.editorDePeliculas = ControladorEditorDePelicula(self.app, self.vista, True)
def onMostrarEditorDePelicula(self, evt):
self.editorDePeliculas = ControladorEditorDePelicula(self.app, self.vista, False)
Implementando la Barra de Navegación
Debemos tener en cuenta, que la Barra de Navegación sólo aparecerá en el modo “Edición” del Editor, por lo tanto modificaremos el método __init__() de la Vista del Editor, para que si lo llamamos en modo “Agregar” la barra no sea mostrada.def __init__(self, parent, app, agregar=True):Como tal vez lo hayan notado, en este método también agregue el código que hace que al abrirse el Editor, la caja de texto del titulo de la película obtenga el enfoque.
self.modelo = app.modelo
self.app = app
self.Dialog = self.app.res.LoadDialog(parent, 'DlgEditorPelicula')
btnAgregarPelicula = xrc.XRCCTRL(self.Dialog, 'btnAceptar')
if(agregar):
titulo_pelicula = xrc.XRCCTRL(self.Dialog, 'txtTitulo')
titulo_pelicula.SetFocus()
barraNavegacion = xrc.XRCCTRL(self.Dialog, 'm_panel2')
barraNavegacion.Show(False)
self.Dialog.Fit()
btnAgregarPelicula.SetLabel('Agregar')
else:
btnAgregarPelicula.SetLabel('Guardar')
titulo_pelicula = xrc.XRCCTRL(self.Dialog, 'txtTitulo')A continuación trabajaremos en la funcionalidad concreta de cada uno de los botones, para lo cual agregaremos los siguientes métodos al Controlador del Editor de Películas.
titulo_pelicula.SetFocus()
def onCargarSiguientePelicula(self, evt):Ahora nos quedara “enlazar” cada uno de estos métodos, con su botón correspondiente. Esto lo haremos agregando el siguiente código en el método __init__() del Controlador del Editor, justo antes de la linea que muestra la ventana.
self.vistaPrincipal.seleccionarSiguientePelicula()
def onCargarPeliculaAnterior(self, evt):
self.vistaPrincipal.seleccionarAnteriorPelicula()
def onCargarPrimeraPelicula(self, evt):
self.vistaPrincipal.seleccionarPrimeraPelicula()
def onCargarUltimaPelicula(self, evt):
self.vistaPrincipal.seleccionarUltimaPelicula()
btnPeliculaAnterior = xrc.XRCCTRL(self.vista.Dialog, 'm_bpButton2')Otro punto que debemos tener en cuenta, es que si bien en el modo “Edición” podremos seleccionar otra película en la Vista Principal, no debería estar habilitada la barra de herramientas ni el menú. Para lograr este comportamiento, agregaremos el método habilitarEdicion() en la Vista Principal.
btnPeliculaSiguiente = xrc.XRCCTRL(self.vista.Dialog, 'm_bpButton3')
btnPrimeraPelicula = xrc.XRCCTRL(self.vista.Dialog, 'm_bpButton1')
btnUltimaPelicula = xrc.XRCCTRL(self.vista.Dialog, 'm_bpButton4')
self.vista.Dialog.Bind(wx.EVT_BUTTON, self.onCargarPeliculaAnterior, btnPeliculaAnterior)
self.vista.Dialog.Bind(wx.EVT_BUTTON, self.onCargarSiguientePelicula, btnPeliculaSiguiente)
self.vista.Dialog.Bind(wx.EVT_BUTTON, self.onCargarPrimeraPelicula, btnPrimeraPelicula)
self.vista.Dialog.Bind(wx.EVT_BUTTON, self.onCargarUltimaPelicula, btnUltimaPelicula)
def habilitarEdicion(self, habilitado=True):Este método lo invocaremos al mostrar el Editor en el modo “Edición”, dentro del método __init__() del Controlador del Editor.
#Deshabilito o habilito la barra de herramientas
barra_de_herramientas = self.frame.GetToolBar()
barra_de_herramientas.Enable(habilitado)
#Deshabilito o habilito el menú
menu_catalogo = self.frame.GetMenuBar()
menu_catalogo.EnableTop(0, habilitado)
.En el caso que el Editor sea llamado en modo “Agregar”, lo que haremos sera mostrar el Dialogo en forma Modal, así la Ventana Principal quedará completamente bloqueada. Para esto modificaremos el método Mostrar() de la Vista del Editor.
.
.
if(agregar):
self.vista.Dialog.Bind(wx.EVT_BUTTON, self.onAgregarPelicula, btnAgregarPelicula)
else:
self.vistaPrincipal.habilitarEdicion(False)
.
.
.
def Mostrar(self, modal=True):Y dado que ahora este método recibe el parámetro “modal”, modificaremos la llamada en el Controlador del Editor, dentro del método __init__().
if modal:
self.Dialog.ShowModal()
else:
self.Dialog.Show()
self.vista.Mostrar(agregar)Para ir finalizando, agregaremos un método al que llamaremos onCerrarrEditorDePelicula() en el Controlador del Editor, el cual se encargara de volver a habilitar la Vista Principal tras cerrar el Editor, y también hará que se deje de escuchar el mensaje 'cambio_item_seleccionado'.
def onCerrarEditorDePelicula(self, evt):Por último, asociaremos el evento que nos indica que la ventana se cerrara; con este método, dentro del método __init__() del Controlador del Editor.
self.vistaPrincipal.habilitarEdicion(True)
Publisher.unsubscribe(self.onSeCambioItemSeleccionado, 'cambio_item_seleccionado')
self.vista.Dialog.Destroy()
self.vista.Dialog.Bind(wx.EVT_CLOSE, self.onCerrarEditorDePelicula, self.vista.Dialog)Y así hemos llegado al final de esta quinta entrega, en la que hemos realizado varios cambios. Dado que la cantidad de modificaciones con relación a la versión anterior, es bastante grande, voy a estar publicando una parte 6, en donde va a estar todo el código completo hasta este punto. Luego de la sexta entrega, trabajaremos en la busqueda de peliculas dentro del Catalogo.
Hasta la próxima!
0 comments
Publicar un comentario