Si has llegado aquí mediante un buscador o por simple casualidad, te cuento que estas en la cuarta parte de un tutorial que empieza AQUI.
Como les había adelantado en la parte anterior, hoy empezaremos a trabajar en el Editor de Películas del Catálogo. Este editor sera el medio por el cual los usuarios podrán tanto agregar películas al catálogo, como editar la información de las que ya se encuentren cargadas. Tal como hicimos con la Ventana Principal, crearemos por un lado la Vista y por otro el Controlador. Dicho esto, empecemos a trabajar.
Codificando la Vista del Editor de películas
La clase que representa la Vista de nuestro Editor la llamaremos VistaEditorDePeliculas. Como les había comentado, el Editor sera invocado para realizar dos funciones distintas: agregar o modificar una película. Para que el Editor “sepa” en que modo lo estamos llamando, le pasaremos un parámetro. El parámetro lo llamaremos agregar y tendrá como valor por defecto True; es decir que si al invocarlo, no especificamos nada, el Editor se abrirá en modo “Agregar Película”. Además del modo en que queremos que se muestre el Editor, también le diremos quien es su ventana padre (en nuestro caso sera la Ventana Principal), y también recibirá una referencia a la aplicación en si, para poder acceder a los recursos (app.res) desde donde cargaremos la interface gráfica del dialogo, y también podremos saber cual es el modelo (app.modelo) de la aplicación. A continuación les muestro el código que implementa lo que les acabo de comentar:import wx
from wx import xrc
class VistaEditorDePelicula:
def __init__(self, parent, app, agregar=True):
self.modelo = app.modelo
self.app = app
self.Dialog = self.app.res.LoadDialog(parent, 'DlgEditorPelicula')
Con esto tenemos nuestro método __init__ casi terminado. Para finalizar agregaremos algo de código, para poder determinar si estamos en modo “Agregar” o “Editar”, y establecer el label del botón que guarda los cambios (btnAceptar) con el texto “Agregar” o “Guardar” según corresponda:
import wx
from wx import xrc
class VistaEditorDePelicula:
def __init__(self, parent, app, agregar=True):
self.modelo = app.modelo
self.app = app
self.Dialog = self.app.res.LoadDialog(parent, 'DlgEditorPelicula')
btnAgregarPelicula = xrc.XRCCTRL(self.Dialog, 'btnAceptar')
if(agregar):
btnAgregarPelicula.SetLabel('Agregar')
else:
btnAgregarPelicula.SetLabel('Guardar')
Por otro lado, debemos tener en cuenta que en caso que el Editor sea abierto en modo “Agregar”, basta con que el dialogo se muestre, pero si se abre en modo “Editar”, los controles del dialogo deben estar cargados con los datos correspondientes a la película que esta seleccionada en la Ventana Principal; para llevar a cabo esta tarea, codificaremos el método cargarPelicula. Este método recibirá el ID que tiene asignado la película en la base de datos, y haciendo uso del Modelo obtendremos los datos de esta, para luego cargar los controles correspondientes del Editor. Veamos como quedaría:
import wxComo pueden ver, el método cagarPelicula, llama al método obtenerInformacionDePelicula del Modelo, pasándole el ID de la película cuyos datos necesitamos. Tras esta llamada, tendremos el resultado en infoPelicula, y con estos cargamos los controles correspondientes al titulo y el año de la misma.
from wx import xrc
class VistaEditorDePelicula:
def __init__(self, parent, app, agregar=True):
self.modelo = app.modelo
self.app = app
self.Dialog = self.app.res.LoadDialog(parent, 'DlgEditorPelicula')
btnAgregarPelicula = xrc.XRCCTRL(self.Dialog, 'btnAceptar')
if(agregar):
btnAgregarPelicula.SetLabel('Agregar')
else:
btnAgregarPelicula.SetLabel('Guardar')
def cargarPelicula(self, idPelicula):
infoPelicula = pelicula.Pelicula()
infoPelicula = self.modelo.obtenerInformacionDePelicula(idPelicula)
titulo_pelicula = xrc.XRCCTRL(self.Dialog, 'txtTitulo')
anio_pelicula = xrc.XRCCTRL(self.Dialog, 'txtAnio')
titulo_pelicula.SetValue(infoPelicula.getTitulo())
anio_pelicula.SetValue(infoPelicula.getAnio())
Por si no lo recuerdan, el método obtenerInformacionDePelicula al que estamos llamando, aún no existe en nuestro Modelo, así que veamos como sería el código de este:
def obtenerInformacionDePelicula(self, idPelicula):Este método, tan sólo ejecuta una consulta a la base de datos para obtener la información de la película cuyo ID coincida con el que le enviamos como parámetro, y luego retorna esta información a quien lo haya invocado.
self.conectar()
self.cursor.execute("SELECT * FROM tblPeliculas WHERE IDPelicula = " + str(idPelicula))
resultado = self.cursor.fetchone()
infoPelicula = pelicula.Pelicula()
infoPelicula.setTitulo(str(resultado[1]))
infoPelicula.setAnio(str(resultado[2]))
self.desconectar()
return infoPelicula
Hasta ahora no tenemos la posibilidad de que se muestre el Editor, así que agregaremos un método a la Vista, llamado Mostrar para llevar a cabo esta tarea:
import wxLuego de terminar con esta clase, pasaremos a desarrollar el Controlador del Editor, el cual se encargara entre otras cosas de enviar a guardar los datos ingresados en los controles del Editor; es por esto que necesitamos crear un método en la Vista, que retorne lo que el usuario haya cargado; así que pasaremos a agregar el método getInfoPelicula:
from wx import xrc
class VistaEditorDePelicula:
def __init__(self, parent, app, agregar=True):
self.modelo = app.modelo
self.app = app
self.Dialog = self.app.res.LoadDialog(parent, 'DlgEditorPelicula')
btnAgregarPelicula = xrc.XRCCTRL(self.Dialog, 'btnAceptar')
if(agregar):
btnAgregarPelicula.SetLabel('Agregar')
else:
btnAgregarPelicula.SetLabel('Guardar')
def cargarPelicula(self, idPelicula):
infoPelicula = pelicula.Pelicula()
infoPelicula = self.modelo.obtenerInformacionDePelicula(idPelicula)
titulo_pelicula = xrc.XRCCTRL(self.Dialog, 'txtTitulo')
anio_pelicula = xrc.XRCCTRL(self.Dialog, 'txtAnio')
titulo_pelicula.SetValue(infoPelicula.getTitulo())
anio_pelicula.SetValue(infoPelicula.getAnio())
def Mostrar(self):
self.Dialog.ShowModal()
import wxEl método getInfoPelicula, simplemente obtiene los valores que el usuario introdujo en los controles y los carga en un objeto de la clase Pelicula, para luego retornarlo como resultado de su ejecución. Aun no hemos creado la clase Pelicula, así que pasemos a ver como seria:
from wx import xrc
class VistaEditorDePelicula:
def __init__(self, parent, app, agregar=True):
self.modelo = app.modelo
self.app = app
self.Dialog = self.app.res.LoadDialog(parent, 'DlgEditorPelicula')
btnAgregarPelicula = xrc.XRCCTRL(self.Dialog, 'btnAceptar')
if(agregar):
btnAgregarPelicula.SetLabel('Agregar')
else:
btnAgregarPelicula.SetLabel('Guardar')
def Mostrar(self):
self.Dialog.ShowModal()
def cargarPelicula(self, idPelicula):
infoPelicula = pelicula.Pelicula()
infoPelicula = self.modelo.obtenerInformacionDePelicula(idPelicula)
titulo_pelicula = xrc.XRCCTRL(self.Dialog, 'txtTitulo')
anio_pelicula = xrc.XRCCTRL(self.Dialog, 'txtAnio')
titulo_pelicula.SetValue(infoPelicula.getTitulo())
anio_pelicula.SetValue(infoPelicula.getAnio())
def getInfoPelicula(self):
infoPelicula = pelicula.Pelicula()
titulo_pelicula = xrc.XRCCTRL(self.Dialog, 'txtTitulo')
anio_pelicula = xrc.XRCCTRL(self.Dialog, 'txtAnio')
infoPelicula.setTitulo(titulo_pelicula.GetValue())
infoPelicula.setAnio(anio_pelicula.GetValue())
return infoPelicula
class Pelicula:De este modo, damos por terminada la Vista del Editor de películas y nos metemos de lleno con su Controlador.
def __init__(self):
self.titulo = ""
self.anio = ""
def setTitulo(self, titulo):
self.titulo = titulo
def getTitulo(self):
return self.titulo
def setAnio(self, anio):
self.anio = anio
def getAnio(self):
return self.anio
Codificando el Controlador del Editor de películas
El controlador del Editor sera el encargado de enviar a agregar o modificar la película según en que estado se encuentre abierto el Editor, es por esto que crearemos en este, los métodos onAgregarPelicula y onModificarPelicula:Claramente los dos métodos son muy parecidos, simplemente obtienen los datos cargados en la Vista a través del método getInfoPelicula que codificamos anteriormente, y llaman a al método agregarPelicula o modificarPelicula del Modelo según corresponda.
def onAgregarPelicula(self, evt):
infoPelicula = self.vista.getInfoPelicula()
self.app.modelo.agregarPelicula(infoPelicula.getTitulo(), infoPelicula.getAnio())
def onModificarPelicula(self, evt):
infoPelicula = self.vista.getInfoPelicula()
self.app.modelo.modificarPelicula(self.idPelicula, infoPelicula.getTitulo(), infoPelicula.getAnio())
Teniendo en cuenta que tenemos dos acciones posibles, debemos “asociar” el botón btnAceptar con una u otra función a la hora de crear la clase, es por esto que en el método __init__ (y al igual que hacíamos con la Vista) le pasamos el parámetro Agregar para determinar en que estado queremos mostrar el Editor, y así llevar a cabo la asociación. Para clarificar esto, veamos como quedaría la clase completa:
from vistas.vistaEditorDePelicula import VistaEditorDePelicula
import wx
from wx import xrc
import pelicula
class ControladorEditorDePelicula:
def __init__(self, app, parent, agregar=True):
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.idPelicula = app.controladorVistaPrincipal.vista.getIDItemSeleccionado()
self.vista.Dialog.Bind(wx.EVT_BUTTON, self.onModificarPelicula, btnAgregarPelicula)
self.vista.cargarPelicula(self.idPelicula)
self.vista.Mostrar()
def onAgregarPelicula(self, evt):
infoPelicula = self.vista.getInfoPelicula()
self.app.modelo.agregarPelicula(infoPelicula.getTitulo(), infoPelicula.getAnio())
def onModificarPelicula(self, evt):
infoPelicula = self.vista.getInfoPelicula()
self.app.modelo.modificarPelicula(self.idPelicula, infoPelicula.getTitulo(), infoPelicula.getAnio())
Pueden ver que el método __init__ comienza creando la Vista (a la cual le pasa los parámetros que tratamos oportunamente), luego determina si estamos en el modo “Agregar” o “Editar” y asocia el botón btnAceptar con el método onAgregarPelicula o onModificarPelicula; y por ultimo hace visible el Editor invocando el método Mostrar de la Vista del Editor. Para terminar, tan solo quiero que presten atención que si estamos en el modo de edición, obtenemos el ID de la película seleccionada en la Ventana Principal, y llamamos al método cargarPelicula de la Vista del Editor pasándoselo como parámetro, de este modo logramos que cuando aparezca el Editor en pantalla, este presente los datos de la película que el usuario quiere modificar.
Con esto terminamos esta cuarta parte del tutorial. En la próxima entrega haremos algunos cambios estéticos a nuestra pequeña aplicación (Agregaremos algunos iconos a la barra de herramientas, menues y botones) y también veremos como hacer para que podamos movernos entre las distintas películas del Catálogo directamente desde el Editor de Películas, sin necesidad de estar cerrándolo para pasar a modificar otra película.
15 comments
Hola Pablo!
Gracias por el tutorial! Tengo una duda, he intentado resolverla buscando por internet pero no se como hacerlo.
Para coger el valor de un Textctrl hago algo como:
NCdensity=(xrc.XRCCTRL(self.frame,'ncdensity').GetValue())
Quiero hacer algo similar pero para saber el valor de una wxChoice.
Muchas gracias!!!!!
Hola Superpeach, para determinar el INDICE del item que esta seleccionado en un wx.choice tenes que usar el metodo GetSelection() y si quieres el TEXTO correspondiente al item seleccionado puedes usar GetStringSelection().
Ej:
indice_seleccionado = xrc.XRCCTRL(self.frame,'m_choice1').GetSelection()
texto_seleccionado = xrc.XRCCTRL(self.frame,'m_choice1').GetStringSelection()
Cualquier otra duda, no dudes en preguntar.
Hasta la proxima!
Pablo Tilli
Muchísimas gracias Pablo!! :D
Muchas gracias por el tutorial Pablo. 3 preguntas:
1.- vas a subir los ejemplos para poder descargarlos?
2.- podrías explicar como enlazas el controlador principal con el del editor de pelicula?
3.- como te organizas: todos los controladores, modelos y vistas mezclados en un mismo directorio? En "from vistas.vistaEditorDePelicula import VistaEditorDePelicula" das a entender que metes todas las vistas en un fichero llamado vistas?
Amigo Gracias por tu excelente tutorial, espero la siguiente parte del tutorial, una pregunta en propiedades del frame en wxformBuild... hay una que dice transparente o algo asi, es para volver transparente el frame? lo active y cuando corri el programa no veo nada nada diferente el frame uso kubuntu 9.10 eso afecta? Espero me respondas Gracias.
ulises
Je corrijo esta en style del frame se llama:wxTRANSPARENT_WINDOW.
ulises
@Anónimo: en el propio programa indica: "The window is transparent, that is, it will not receive any paint events. Windows only." -> "Windows only" quiere decir que solamente funciona en Windows, o sea que en Linux no vemos nada diferente. Saludos.
Si me acabo de dar cuenta que decepcion, grax @Anonimo.
ulises
@ulises: Como bien te ha dicho Roger, wxTRANSPARENT_WINDOW sólo tiene sentido en Windows. Saludos!
@Roger: Hola Roger, estas son las respuestas a tus preguntas:
1.- vas a subir los ejemplos para poder descargarlos?
Me he dado cuenta (que al menos en mi caso) aprendo mucho mas cuando al seguir un tutorial, tengo que escribir y probar el código paso a paso, que si tan solo lo bajo y lo ejecuto, por esto es que no subo los archivos. Claro esta que en algunos casos uno no dispone del suficiente tiempo para esto, así que si lo deseas no tienes mas que pasarme tu e-mail y te lo envío, o si bien no quieres hacer publica tu dirección de correo, escribeme directamente al mio.
2.- podrías explicar como enlazas el controlador principal con el del editor de película?
Realmente te agradezco por esta pregunta, porque me he dado cuenta que no lo había explicado. La idea es completar los métodos onMostrarAgregarPelicula y onMostrarEditorDePelicula del Controlador de la Vista Principal. Estos métodos los vimos en la parte 3 del tutorial y habían quedado así:
def onMostrarAgregarPelicula(self, evt):
wx.MessageBox("Mostrar el Editor de Películas para agregar una película")
def onMostrarEditorDePelicula(self, evt):
wx.MessageBox("Mostrar el Editor de Películas para modificar la película seleccionada")
Es decir que solo mostraban un mensaje con lo que debian hacer. Para que hagan lo que queremos, quedarían así:
def onMostrarAgregarPelicula(self, evt):
self.editorDePeliculas = ControladorEditorDePelicula(self.app, self.vista.frame, self.vista.res)
def onMostrarEditorDePelicula(self, evt):
self.editorDePeliculas = ControladorEditorDePelicula(self.app, self.vista.frame, False)
También debemos importar la clase controladorEditorDePelicula:
from controladores.controladorEditorDePelicula import ControladorEditorDePelicula
Ni bien tenga un tiempo, voy estar integrando esto en el tutorial.
3.- como te organizas: todos los controladores, modelos y vistas mezclados en un mismo directorio? En "from vistas.vistaEditorDePelicula import VistaEditorDePelicula" das a entender que metes todas las vistas en un fichero llamado vistas?
Te cuento que no esta todo mezclado en el mismo directorio. La estructura es la siguiente:
CatalogoDePeliculas
--> controladores
------> __init__.py
------> controladorEditorDePelicula.py
------> controladorVistaPrincipal.py
--> vistas
------> __init__.py
------> vistaEditorDePelicula.py
------> vistaPrincipal.py
--> catalogo.py
--> modelo.py
--> pelicula.py
--> gui.xrc
Bueno Roger, espero haber podido aclarar un poco tus dudas. Si tienes otra consulta o algo no que realmente claro de las anteriores, no tienes mas que escribir nuevamente.
Saludos,
Pablo Tilli.
Gracias Pablo, por compartir tus conocimientos y por atender mis consultas.
Saludos,
roger
Estimado Pablo:
He encontrado en tu blog el elemento coordinante de un rompecabezas que tenía en mi mente; ese elemento coordinante es la programación orientada a eventos, es decir como se relacionaban Python, wxPython y Mysql. En tus tres tutoriales (Organización de widgets en wxPython – Utilizar archivos de recursos (XRC) con wxPython y Preparando un tutorial para crear una pequeña aplicación completa) y un paneo general por las acciones mas comunes al trabajar con una base de datos engloba en forma general el concepto de una forma de programación en Python. En mi caso particular lo voy a utilizar para migrar un sistema hecho en foxpro 2.5 para DOS. Gracias Pablo por compartir tus conocimientos. Seguí adelante y esperamos la quinta parte de crear una pequeña aplicación completa usando wxPython
Saludos
JOSE
Gracias Hermano excelente Tutorial!!!!
Una pregunta estoy haciendo un editor de texto con wxTxtCtrl de wxpython y quiero que se vea los números de linea y no encuentro ningún método para esto en el wxtextctrl o es que no lo tiene o tengo que hacer la visibilidad de los números de linea de otra forma?
Cualquier información sera bienvenida
Hola Pablo
Tengo un problema con los menus, te cuento quiero poder modificar el texto de los menus de mi aplicación desde el programa, y no se como hacer la referencia a la m_menubar del archivo XRC de Wxformbuilder. He estado ha punto de ponerme ha generar los menus desde codigo.
pablo seria de mucha utilidad que publiques el codigo fuente completo de este modo podriamos hacer las pruebas directamente mil gracias por tu tirmpo amigo sigue adelante.
ha sobre las dudas de nuestros amigos estuve buscando y encontre esta version que la puenden descagar:
para que todo funcione deben instalar:
wxFormBuilder_v3.1.68-rc1 para windows
wxPython2.8-win32-unicode-2.8.10.1-py26
Bueno yo uso como editor el
Ulipad version 4
exelente Editor
Saludos Pablo, buen tutorial, estoy muy agradecido y aquí me tienes rezando por la siguiente entrega.
Publicar un comentario