jueves, 19 de marzo de 2009

Leccion No. 9

Y hasta que por fin se hace realidad el tutorial No. 9 de python y wxpython con VisualWx.

Bueno parece que comenzamos este año con la misma versión de VisualWx, al parecer o son muy pocas las donaciones o practicamente nulas, empezando por mi que ahora me encuentro buscando empleo... je de una vez la cuña... por si alguien sabe de un buen empleo :)

Con el tutorial No. 9 se pretende que aprendamos sobre el manejo de formularios con pestañas/hojas/fichas de ahora en adelante yo las llamaré pestañas.

El material que utilizaremos para este tutorial es el siguiente:

- Una base de datos (yo la llame tutorial9) con la siguiente estructura:

CREATE TABLE cargos (
id tinyint(3) unsigned NOT NULL auto_increment,
cargo varchar(30) NOT NULL,
asignacion int(6) unsigned NOT NULL,
PRIMARY KEY (id)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

CREATE TABLE empleados (
id tinyint(6) unsigned NOT NULL auto_increment,
documento int(12) unsigned NOT NULL,
nombre1 varchar(25) NOT NULL,
nombre2 varchar(25) default NULL,
apellido1 varchar(25) NOT NULL,
apellido2 varchar(25) default NULL,
cargo varchar(30) NOT NULL,
PRIMARY KEY (id)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;


CREATE TABLE nomina (
id tinyint(6) unsigned NOT NULL auto_increment,
fecha date NOT NULL,
empleado int(12) unsigned NOT NULL default '0',
dtrabajados int(2) unsigned NOT NULL,
sdevengado int(6) unsigned NOT NULL,
PRIMARY KEY (id)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;


Creamos una nueva carpeta, abrimos el VisualWx, nuevo proyecto con MDI y lo guardamos en la carpeta que acabamos de crear.

A la carpeta la he llamado tutorial9 y al proyecto lo he denominado nomina (claro que no es un software de nómina es solo una diminuta muestra de lo que se puede hacer con Python, VisualWx, las Wx y MySQL).

Una vez activado el proyecto procedemos a darle forma iniciando con la creación del menú que debe permitirnos abrir dos formularios (cargos y empleados), además de la opción para salir.

Debemos tener hasta el momento algo parecido (no necesariamente igual) a esto:

Ahora vamos a proceder con el diseño y la programación del formulario Cargos, para que te bases te presento el mio:
Recuerda es algo básico lo que estamos haciendo aquí; si tu quieres agregarle funcionalidades pues.... no hay ningún problema, el límite es tu imaginación.

Configuramos los focos (el foco inicial debe aparecer en el txt del nombre del cargo ya que el código es autonumérico y de solo lectura), agragamos el código para que se active desde el menú y luego hacemos el código para los tres botones:

El de guardar:
def guarda_info(self,event): #init function
#add your code here
cargo = self.txt_cargo.GetValue()
asignacion = self.txt_asignacion.GetValue()

sql = c.execute('insert into cargos values(%s,%s,%s)',('',cargo,asignacion))
res = c.fetchall()

dlg = wx.MessageDialog(self,u"Registro almacenado con éxito",u"NUEVO REGISTRO", wx.OK | wx.ICON_INFORMATION)
dlg.ShowModal()
dlg.Destroy()

self.txt_cargo.SetLabel("")
self.txt_asignacion.SetLabel("")
self.txt_cargo.SetFocus()

return #end function


El botón eliminar:
def elimina_cargo(self,event): #init function
#add your code here
cargo = self.txt_cargo.GetValue()
asignacion = self.txt_asignacion.GetValue()

sql = c.execute('DELETE FROM cargos WHERE cargo=%s AND asignacion=%s',(cargo,asignacion))
res = c.fetchall()

dlg = wx.MessageDialog(self,u"Registro eliminado con éxito",u"ELIMINACIÓN DE REGISTRO", wx.OK | wx.ICON_INFORMATION)
dlg.ShowModal()
dlg.Destroy()

self.txt_cargo.SetLabel("")
self.txt_asignacion.SetLabel("")
self.txt_cargo.SetFocus()

return #end function


El botón cerrar:
def cerrar_cargos(self,event): #init function
#add your code here
self.Close()
return #end function


Ahora lo que debes hacer es ingresar varios cargos con varias asignaciones salariales, procura ingresar cerca de 5 cargos.

Luego de esto, vamos a diseñar el formulario que más nos interesa, el de Empleados y Nómina.

Lo primero es lo primero, agregamos un form MDIChild, le damos un título, color y formato.

Luego el código para que se nos active desde el menú.
Y ahora el objetivo de este tutorial....


En la ventana components seleccionamos la opción Notebook, te darás cuenta que aparecen tres (3) elementos más, entre ellos otro denominado Notebook, dale doble clic para que aparezca en el form, lo estiras y lo ubicas dentro del form.

Ese va a ser la “base”, sobre la cual vamos a agragar nuestras pestañas.

Vamos a asignarle un nombre, en la ficha properties nos ubicamos en la propiedad Name y le asginamos un nombre, yo le he puesto base.

Ahora para agregar nuestra primera pestaña asegúrate de que el componente base está seleccionado.

Ahora en la ficha Components abre la carpeta Panel, allí encontrarás un componente denominado Control, dá doble clic sobre él y debes tener algo así:

Te he marcado con elipses rojas los puntos sobre los cuales estamos trabajando.

Vamos a cambiar el nombre que aparece en la pestaña 0 (page n:1) por empleados:

Lo primero es cambiar el nombre al nuevo elemento que ingreso, el que ahora aparece debajo de base en la ficha Project; vamos a cambiarla por pagina1, desde la ficha Properties.

En esa misma ficha de Properties buscamos la propiedad Text Tab y al frente de ésta escribimos empleados. Nos debe aparecer algo como esto:

Para crear la siguiente pestaña debemos hacer clic en el control denominado base que se encuentra en la ficha Project, estándo ya activado base, volvemos a dar doble clic sobre el componente Control para que nos aparezca la segunda pestaña.

Repetimos el procedimiento para cambiar nombres y que nos parezca en la pestaña la palabra Pago de Nómina.

No te olvides de estar guardando.

Ahora procedermos a ubicar los controles que necesitamos. Para la pestaña empleados vamos a ubicar los controles que aparecen en la imagen.

Para que los componentes seleccionados te aparezcan donde deseas debes tener muy en cuenta de seleccionar en la ficha Project sobre cuál componente estás trabajando. Más claro: si quieres ubicar los componentes para la pestaña empleados, debes tener activado en la ficha Project, el componente pagina1 que se encuentra de base.

Y aprovechamos también para ubicar los botones.

Ahora vamos a ubicar los controles para la pestaña Pago de Nómina:

Ahora vamos a programar los focos, llenar el combo y hacer los respectivos cálculos.

Para poder que los componentes tengan la propiedad de cambiar de foco cuando presionamos la tecla enter, tab o intro debemos señalar el el componente (vamos a comenzar señalando el txt_documento) y en la ficha properties buscamos la propiedad Style, damos doble clic para que nos aparezca la ventana de estilos.

Esta ventana lo que hace es agregar algunas propiedades/comportamientos adicionales a los componentes. Vamos a señalar los dos estilos que aparecen marcados en la imagen (wxTE_PROCESS_ENTER y wxTE_PROCESS_TAB).

Repetimos esta acción con todos los componentes (menos aquellos componentes [txt_asignacion y txt_total] que van a ser de lectura).

En caso del combo, demebos activar los estilos wxCB_DROPDOWN y wxTE_PROCESS_ENTER (no te preocupes si cambia de aspecto).

Para el caso de los de sólo lectura debemos señalar wxTE_READONLY.

Muy bien, ahora vamos a programar el llenado del combo para que al hacer clic en él se nos muestre la lista de cargos disponibles.

Recuerda importar la base de datos y que para llenar el combo utilizamos el evento EVT_LEFT_DOWN:

def llena_combo(self,event): #init function
#add your code here
sql = c.execute('SELECT cargo FROM cargos ORDER BY cargo ASC')
res = c.fetchall()

self.cmbCargo.Clear()

for i in res:
self.cmbCargo.Append(str(i[0]))

event.Skip()

return #end function


Ahora programamos los focos de los componentes de la manera tradicional.

Debemos hacer una funcional adicional para cuando hacemos clic en el txt_asignacion, lo podemos hacer en el evento EVT_SET_FOCUS:

def recupera_valor(self,event): #init function
#add your code here
cmb = self.cmbCargo.GetValue()

sql = c.execute('SELECT asignacion FROM cargos WHERE cargo=%s',cmb)
res = c.fetchone()
fil = int(c.rowcount)

if fil==0 or fil=='':
self.txt_asignacion.SetLabel("0")
else:
basico = str(res[0])
self.txt_asignacion.SetLabel(basico)

event.Skip()

return #end function


Y esta es la función para cuando se txt_total recibe el foco:
def calcula_total(self,event): #init function
#add your code here
basico = self.txt_asignacion.GetValue()
dt = self.txt_dt.GetValue()

basico = int(basico)

devengado = basico/int(dt)

self.txt_total.SetLabel(str(devengado))

event.Skip()

return #end function


Falta programar los botones....

Con este formulario de nómina se registran datos en dos tablas, en empleados y nomina.

Código del botón guardar:

def guarda_datos(self,event): #init function
#add your code here
doc = self.txt_documento.GetValue()
nom1 = self.txt_nom1.GetValue()
nom2 = self.txt_nom2.GetValue()
ape1 = self.txt_ape1.GetValue()
ape2 = self.txt_ape2.GetValue()
cargo = self.cmbCargo.GetValue()
asigna = self.txt_asignacion.GetValue()
dt = self.txt_dt.GetValue()
total = self.txt_total.GetValue()
fec = self.txt_fecha.GetValue()

#Guardamos en la tabla empleados
sql1 = c.execute('INSERT INTO empleados VALUES(%s,%s,%s,%s,%s,%s,%s)',('',doc,nom1,nom2,ape1,ape2,cargo))
res1 = c.fetchall()

#Guardamos en la tabla nomina
sql2 = c.execute('INSERT INTO nomina VALUES(%s,%s,%s,%s,%s)',('',fec,doc,dt,total))
res2 = c.fetchall()

if res1<>None and res2<>None:
dlg = wx.MessageDialog(self,u'Registro almacenado con éxito','Nuevo Registro',wx.OK | wx.ICON_INFORMATION)
dlg.ShowModal()
dlg.Destroy()

self.txt_documento.SetLabel("")
self.txt_nom1.SetLabel("")
self.txt_nom2.SetLabel("")
self.txt_ape1.SetLabel("")
self.txt_ape2.SetLabel("")
self.cmbCargo.SetLabel("")
self.txt_asignacion.SetLabel("")
self.txt_dt.SetLabel("")
self.txt_total.SetLabel("")

self.txt_documento.SetFocus()
else:
dlg = wx.MessageDialog(self,u'Error al guardar datos','ERROR',wx.OK | wx.ICON_EXCLAMATION)
dlg.ShowModal()
dlg.Destroy()
self.txt_documento.SetFocus()

return #end function


Obviamente el código puede ser mejorado, colocar restricciones, etc; pero por ahora para un simple ejemplo y para aprender a manejar las pestañas creo que esto va a servir.

Si desean abrir una ventana desde este form deben tener en cuenta lo siguiente:
1.El formulario no debe ser un MDIChild sino un form tipo Dialog.
2.Para invocarlo (abrirlo desde otro form) utilizas un botón o un evento y lo abres como abriendo cualquier ventana de diálogo.

Es todo por ahora.

4 comentarios:

Anónimo dijo...

Muchas gracais por continuar con el curso!

Anónimo dijo...

lo mejor que has creado amigo
mil gracias seria preciso que cada programador de python suba sus fuentes pues de ellos se puede aprender mas rapido y tambien se logra controlar todos los eventos lo preciso es dejar codigo fuente terminado si todos lo hariammos se ganaria mucho las cosas serian mucho mejores gracias amigo por todo continua asi yo te seguire los pasos..

att Ricardo

Anónimo dijo...

Hola!,

estoy programando algo con visualwx y estoy teniendo problemas en una parte, el error que me tira es algo asi como "ascci can't decode byte at position ....", tienes idea de como solucionarlo? probe haciendo .encode('utf-8') del string pero nada, sigue tirando el error.

Gracias!.

Anónimo dijo...

Hola!,

Quisiera saber si has probado BOA Constructor como RAD para Python.

Saludos.