jueves, 25 de septiembre de 2008

Lección No. 6

2 comentarios
En esta lección aprenderemos a crear un form MDI, repasaremos temas de conexión con MySQL, crearemos una barra de menú con sus respectivos ítems, shorcuts y funciones y tendremos un breve código de excepciones (aunque no se si me va a funcionar).


Material para esta lección

Debemos crear una base de datos denominada leccion6 con la siguiente estructura:

CREATE TABLE especie (
id int(4) unsigned NOT NULL auto_increment,
nombre varchar(12) NOT NULL default '0',
KEY id (id)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;


CREATE TABLE mascotas (
id varchar(4) unsigned NOT NULL,
nombres varchar(30) NOT NULL,
familia varchar(15) NOT NULL,
especie varchar(15) NOT NULL,
sexo varchar(2) NOT NULL,
fnace date NOT NULL,
fmuere date default NULL,
KEY id (id)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;


CREATE TABLE sexo (
id int(4) unsigned NOT NULL auto_increment,
nombre varchar(2) NOT NULL,
KEY id (id)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

Llenamos la tabla especie con todas las especies de animales que se te ocurran: canino, felino, ave, reptil, equino, pez, etc....

Llenamos la tabla sexo con: F para femenino, M para masculino y NA para los indeterminados o casos donde no aplican.


Lo primero es lo primero, creamos una carpeta nueva para esta lección luego entramos al VisualWx, hacemos clic en el menú File y seleccionamos New Project cuidado es el New Project no el New Empty Project.

Nos aparecerá una ventana (Template) allí señalamos WX_MDI_Python, ubicamos la carpeta que hemos creado anteriormente y guardamos el proyecto, yo le he puesto leccion6

Ahora, ejecuta el programa (F5).

Observarás entonces una ventana dentro de otra, algo como esto:

Lo primero que vamos a organizar es que no nos aparezca esa ventana una vez se inicie nuestro programa, para ello debemos hacer doble clic en MyFrame que es el que actúa como formulario principal (el form madre por llamarlo de alguna manera) que contendrá a los demás formularios.

Teniendo este form en modo edición, hacemos clic en la ficha Python (si la del centro que nos lleva al código de python) y buscamos esta función:

def initAfter(self):
#add your code here
self.child=frmChild.frmChild(self,-1)
return

Podemos comentar la línea self.child=frmChild.frmChild(self,-1) o simplemente eliminarla, sin embargo fíjate muy bien como está escrita ya que la tomaremos como guía para activar nuestros forms desde el menú que más adelante crearemos.

Yo normalmente la elimino ya que casi casi me se el código de memoria, sin embargo al comienzo solo la dejaba comentada aunque no faltará quien sugiera que es mejor eliminarla ya que incrementa el número de líneas, memoria, etc, etc.

Si ejecutas nuevamente el programa notarás que ya no aparece el form de adentro (frmChild).

Si todo marcha bien entonces vamos a proceder a trabajar con el form frmChild. Lo cargamos para su edición, cambiamos su color, tamaño de fuente y ubicamos los siguientes controles:


Será necesario sacar la lista??? no creo.

Al cuadro de texto fecha de nacimiento y fecha de fallecimiento en la ficha propiedades en Text ponle 0000-00-00 para indicar que es el formato de fecha que utilizaremos año-mes-dia ó más técnicamente yyyy-mm-dd

Luego programamos los focos de los controles, empezando por el txt del código y terminar en el txt de fecha de fallecimiento.

Cómo lo hago??? Revisa la lección No. 5

Los botones Actualizar y Eliminar deben comenzar desactivados.

No olvides verificar los focos una vez programados.

Botón Guardar:

def guarda_datos(self,event): #init function
#add your code here
id = self.txt_codigo.GetValue()
nom = self.txt_nombre.GetValue()
flia = self.txt_familia.GetValue()
esp = self.cmb_especie.GetValue()
sex = self.cmb_sexo.GetValue()
fnace = self.txt_fnace.GetValue()
fmuere = self.txt_fmuere.GetValue()

"""Obligo a que el usuario ingrese los campos
que considero obligatorios"""
if id<>'' and nom<>'' and flia<>'' and esp<>'' and sex<>'':
"""Hay una condicón con la que deberíamos
tener un poco de cuidado y es el DatePicker fnace,
la condición sería que si la fecha es igual a la de
hoy le pregunte al usuario si es correcta o no,
pero ese tipo de situaciones la veremos en otros
tutoriales, hoy la obviaremos a propósito""
sql = c.execute('INSERT INTO mascotas(id,nombres,familia,especie,sexo,fnace,fmuere) \
VALUES(%s,%s,%s,%s,%s,%s,%s)' ,(id,nom,flia,esp,sex,fnace,fmuere))
res = int(c.rowcount)

"""Si la consulta arroja un número de filas
diferentes a 0, que muestre un mensaje"""
if res<>0:
w = wx.MessageDialog(self,u"Registro almacenado con éxito","REGISTRO ALMACENADO",wx.OK | wx.ICON_INFORMATION)
w.ShowModal()
w.Centre()
w.Destroy()

self.txt_codigo.SetLabel('')
self.txt_nombre.SetLabel('')
self.txt_familia.SetLabel('')
self.cmb_especie.SetLabel('')
self.cmb_sexo.SetLabel('')
self.txt_fnace.SetLabel('')
self.txt_fmuere.SetLabel('')

self.txt_codigo.SetFocus()
else:
w = wx.MessageDialog(self,u"Faltan datos por ingresar","ERROR DATOS",wx.OK | wx.ICON_EXCLAMATION)
w.ShowModal()
w.Centre()
w.Destroy()

self.txt_codigo.SetFocus()

return #end function

Aclaro que los nombres de los controles deben ser los que Ud. utilizo, o sea, reemplace todo lo que dice self.... por self.elnombredetucontrol

Antes de ejecutar para probar el código que acabamos de digitar debemos crear una barra de menú con su respectivo menú para abrir este form desde .... el menú claro. Lo hacemos de la siguiente manera:

Seleccionamos la ficha MyFrame:


Luego, clic en la ficha Menu:

Al hacer clic con el botón derecho del mouse en el espacio blanco debajo de la ficha Menu, nos aparecerá la opción para crear/adicionar una barra de menú o un menú. Para nuestro caso debemos seleccionar la opción Add Menu Bar.

Al seleccionar esta opción puedes observar como aparece inmediatamente en el form principal (MyFrame) una barra de menú.

Si quieres le cambias el nombre en la propiedad Name, yo normalmente la dejo tal cual.

Ya es hora de crear los diferente ítems de los menús que vamos a tener.

Para empezar hacemos clic con el botón derecho del mouse sobre menubar o como quieras que le hayas puesto. Nos aparecerán las opciones Add Menu y Delete (creo que no hay mucho que explicar aquí).

Clic en Add Menu:
Por supuesto a este si hay que cambiarle el nombre, entonces nos vamos a las propiedades y le cambiamos en la opción Title por Principal. Ejecutamos para ensayar y veremos nuestra ventana parecida a esta:

Ya tenemos Principal, el menú Window que se crea automáticamente. Si haces clic en principal no va a pasar ya que falta agregrar los items del menú que es lo vamos a hacer en este momento:

Hacemos clic con el botón derecho sobre “Principal”, te fijas bien en las opciones que se muestran ya que son bien didácticas; de estas opciones vamos a seleccionar Add Item que agrega un “item” al menú denominado “Principal”. Fíjate también en cómo se va formando un árbol con los diferentes menús, ítems y submenús.

Una vez agregado el ítem vamos a la ficha de propiedades y cambiamos en la opción Title por Mascotas, ahora tu menú debe lucir así:

Y si ejecutas el programa, algo como esto:

Cada vez que quieras agregar un ítem al menú Principal, o sea, que quieras que aparezca debajo así como Mascotas, deberás hacer clic derecho sobre la palabra “Principal” en la ficha Menú. También podemos agregar separadores y cambiar de posición los ítems del menú.

A ver si me han entendido. Como prueba, nuestro menú deberá lucir así:

Para crear otro menú digamos Auxiliar (por ejemplo), debemos hacer clic derecho en la opción Menu Bar y proceder como en el caso anterior.

Te estarás preguntado cómo hacemos un submenú, parecido al que podemos encontrar cuando hacemos clic en cualquier menú que tenga la palabra seguida de un >. Fácil, debajo del menú, por ejemplo de Auxiliar, clic derecho Add Menu, das el nombre en propiedades Title, luego agregas items a ese submenú que acabas de crear y ya está.

Bueno, si tienes claro hasta aquí, podemos proseguir, sino enviame un mail para tratar de aclarar tus dudas.

Hasta el momento nuestro menú no hace nada, hagas clic donde lo hagas no hace nada, pues entonces vamos a programar nuestro menú.

Selecciona la opción Mascotas de la ficha Menu.

Haz clic en la ficha Events botón E y en la opción EVT_MENU asigna un nombre a la función, yo le he puesto ver_mascotas; luego vas a la ficha Python, buscas la función y escribes lo siguiente:

def ver_mascotas(self,event): #init function
#add your code here
self.child=frmChild.frmChild(self,-1)
self.child.Centre()
return #end function

Otro código que hace lo mismo es:

def ver_mascotas(self,event): #init function
#add your code here
w = self.frmChild.frmChild(self,-1)
w.Centre()
return #end function

Y cuando se utilizan cuadros de diálogo que tiene la propiedad Modal se puede utilizar:

def ver_mascotas(self,event): #init function
#add your code here
#Si este form fuera del tipo dialogo
w = self.frmChild.frmChild(self,-1)
w.ShowModal()
w.Centre()
w.Destroy()
return #end function


Cómo quieras está bien, yo me quedo con la segunda opción. Ahora para que pueda ser ejecutado el formulario de mascotas, debemos digitar:

#[inc]add your include files here
import frmChild
#[inc]end your include

En la parte superior del código de MyFrame.

Ahora ejecuta el programa y haz clic en la opción Mascotas del menú Principal y obtendrás algo como esto:

Vamos a terminar de programar nuestro formulario de Mascotas, vamos con los combobox.

Antes de proceder con los combos vamos a la ficha Python de este formulario y en la parte superior digitamos:

#[inc]add your include files here
import MySQLdb as con
db = con.connect(host='localhost',user='root',passwd='tuclave',db='leccion6')
c = db.cursor()
#[inc]end your include

Recuerda que este código es el que nos permitirá interactuar desde Python con MySQL.

Ahora si nos vamos a los combos.

Seleccionamos FrmChild, nos cambiamos a modo diseño y hacemos clic en el combobox de especie.

Una vez seleccionado el combo, hacemos clic en la ficha Events botón B y buscamos el evento EVT_LEFT_DOWN asignamos un nombre a la función (yo le he puesto llena_especie), nos pasamos a la ficha Python y buscamos la función para escribir:

def llena_especie(self,event): #init function
#add your code here
sql = c.execute('SELECT nombre FROM especie ORDER BY nombre asc')
res = c.fetchall()
res1 = int(c.rowcount) #Devuelve el número (entero) de filas

"""Limpia el combo antes de ejecutar la
consulta y con esto evitamos que se dupliquen
los contenidos de los combos cada vez que se
haga clic en ellos"""
self.cmb_especie.Clear()

"""Verificamos que la consulta tenga al menos
una fila"""
if res1<>0:
for i in res:
#Agregamos el resultado al combo
self.cmb_especie.Append(str(i[0]))
event.Skip()

return #end function

Ejecuta el programa y verifica que al hacer clic en el combo de especie se despliegue las especies que antes le agregamos a la tabla.

Vamos a ingresar información en nuestro formulario de mascotas (por ahora metamos solo 1 registro):

(Cualquier parecido con la realidad es pura coincidencia)


Ahora vamos a crear una función para que al abandonar el campo código verifique si ya existe el código que se está asignado, si es así que cargue los datos de ese registro, de lo contrario que continúe con el proceso de registro.

Hacemos clic en el campo código, luego en la ficha Events buscamos EVT_KILL_FOCUS, damos un nombre a la función (yo le he puesto consulta_codigo) buscamos luego la función y allí escribimos:

def consulta_codigo(self,event): #init function
#add your code here
ind = self.txt_codigo.GetValue()

sql = c.execute('SELECT * FROM mascotas WHERE id=%s',(ind))
res = c.fetchall()
resX = int(c.rowcount)

if resX<>0:
for i in res:
self.txt_nombre.SetLabel(str(i[1]))
self.txt_familia.SetLabel(str(i[2]))
self.cmb_especie.SetLabel(str(i[3]))
self.cmb_sexo.SetLabel(str(i[4]))
self.txt_fnace.SetValue(str(i[5]))
self.txt_fmuere.SetLabel(str(i[6]))

self.bt_guardar.Enable(False)
self.bt_actualizar.Enable(True)
self.bt_eliminar.Enable(True)
event.Skip()

return #end function

Ejecutamos el programa, abrimos el formulario de mascotas y el campo código digitamos el número 1 o el código que le hayas dado a la mascota; si este código es localizado en la base de datos se cargarán los datos de ese registro, desactivará el botón guardar y activará actualizar y eliminar.

Vamos a suponer que necesitamos corregir la fecha de nacimiento, entonces el código del botón actualizar será el siguiente:

def actualiza_datos(self,event): #init function
#add your code here
id = self.txt_codigo.GetValue()
nom = self.txt_nombre.GetValue()
fam = self.txt_familia.GetValue()
esp = self.cmb_especie.GetValue()
sex = self.cmb_sexo.GetValue()
fna = self.txt_fnace.GetValue()
fmu = self.txt_fmuere.GetValue()

try:
#Acción potencialmente errónea
fmu='None'
except:
#Tratamiento del error
fmu='0000-00-00'

sql = c.execute('UPDATE mascotas SET nombres=%s,familia=%s,especie=%s,sexo=%s,fnace=%s,fmuere=%s WHERE id=%s',(nom,fam,esp,sex,fna,fmu,id))
res = c.fetchone()

w = wx.MessageDialog(self,u"Registro almacenado con éxito","ACTUALIZACION",wx.OK | wx.ICON_INFORMATION)
w.ShowModal()
w.Centre()
w.Destroy()

self.txt_codigo.SetLabel('')
self.txt_nombre.SetLabel('')
self.txt_familia.SetLabel('')
self.cmb_especie.SetLabel('')
self.cmb_sexo.SetLabel('')
self.txt_fnace.SetLabel('')
self.txt_fmuere.SetLabel('')

self.txt_codigo.SetFocus()

return #end function


Y si lo que quisieramos es eliminar el registro? Entonces el código en el botón eliminar sería:
def elimina_datos(self,event): #init function
#add your code here
id = self.txt_codigo.GetValue()

resp = wx.MessageBox("Realmente desea eliminar este registro?","CONFIRMAR ELIMINACION",wx.YES_NO)
if resp==wx.YES:
sql = c.execute('DELETE FROM mascotas WHERE id=%s',(id))

w = wx.MessageDialog(self,u"Registro eliminado con éxito","ELIMINACION",wx.OK | wx.ICON_EXCLAMATION)
w.ShowModal()
w.Centre()
w.Destroy()

self.txt_codigo.SetLabel('')
self.txt_nombre.SetLabel('')
self.txt_familia.SetLabel('')
self.cmb_especie.SetLabel('')
self.cmb_sexo.SetLabel('')
self.txt_fnace.SetLabel('')
self.txt_fmuere.SetLabel('')

self.txt_codigo.SetFocus()
else:
self.txt_codigo.SetFocus()


return #end function

Y por último, el código para el botón cerrar: self.Close()

Ahora lo que vamos a hacer es agregar teclas rápidas a nuestro menú, para ello debes tener seleccionado el MyFrame.

Abre la ficha Menu.
Clic en la opción “Mascotas”
Clic en la ficha propiedades
En la propiedad denominada Shorcut digitaremos Ctrl+M esto hará que cuando presionemos las teclas Control y M se abrirá el form de mascotas.

Hagamos lo mismo con la opción Terminar, sólo que a esta le escribiremos en la propiedad Shorcut F10.


Ejecutamos el programa y probamos primero presionando las teclas Crtl+M, se nos debe abrir el form. Cierralo y prueba presionando la tecla F10, se debe salir totalmente del programa.

Creo que es todo por ahora.


Para una próxima lección espero poder trabajar con el datepicker que en esta ocasión me pidio papeles y por más que pregunte en la lista no pude con este controlcito.