viernes, 5 de diciembre de 2008

Código fuente lección No. 8

2 comentarios
Aquí se encuentra el código fuente de la lección No. 8 así como los demás archivos:

http://www.mediafire.com/file/bqt01uyj2fi/L8.7z
http://www.mediafire.com/file/2entlj4tykz/Leccion No 8.odt
http://www.mediafire.com/file/qdnn1ndmym2/Leccion No 8.pdf
http://www.mediafire.com/file/nmmytmzfyr1/ReportLab.pdf

Lección No. 8

6 comentarios
Nuevamente retomaremos la lección 6 con sus últimas modificaciones, o sea, la de la Lección No. 7, con el fin de aprender a hacer reportes de dos tipos: en html para visualizar en el navegador y en formato pdf.



Materiales para esta lección
El material de la lección número 6
El ReportLab que lo encontramos en.....
2 iconos de 16x16 para el menú reporte html y reporte pdf


Lección No. 8
Recuperamos la última modificación que reposa en la lección No. 7, creamos un menú denominado Reportes y debajo de éste se mostrarán las opciones: Formato html y Formato Pdf, agregamos los íconos para el menú.

Algo parecido a esto es lo que debemos tener:


Y sin más preámbulos vamos a programar el menú Formato html; creamos entonces una función (ya debes saber cómo crear una función para un menú, si no es así entonces te recomiendo que leas las lecciones anteriores) a la que denominaremos genera_html y este es el código:

En la parte superior del código debemos colocar las librerías que vamos a utilizar, así como configurar la conexión a MySQL:

import MySQLdb as con
db = con.connect(host='localhost',user='root',passwd='12345678',db='leccion6')
c = db.cursor()
import subprocess
import sys
import datetime
import os

Buscamos la función que acabamos de crear y digitamos nuestro código:

def genera_html(self,event): #init function
#add your code here
self.imprime()
f = open("C:/REPORTES/mascotas.html", "w")
f.write(self.cadena)
f.close()
if sys.platform == "win32":
subprocess.Popen('explorer C:\\REPORTES\\mascotas.html', shell=True)
else:
subprocess.Popen('firefox C:\\REPORTES\\mascotas.html', shell=True)
return #end function

El anterior código lo que hace es llamar a una función denominada imprime() [que debemos crear enseguida], abrir un archivo en modo de escritura (“w”) ubicándolo en la carpeta REPORTES que se encuentra en la raíz del C: (que no te pase, de una vez y antes de ejecutar el programa crea una carpeta en el disco duro donde se almacenarán los reportes), luego verifica si la plataforma sobre la que estamos trabajando es basada en win32 para abrir el internet explorer, sino abre el Firefox.

Ahora debemos crear la función imprime(), para ello solo buscate un espacio libre (puede ser debajo de la función anterior) y escribe como sigue:


La anterior función lo que hace es tomar una variable para concatenarla utilizando código html en la cual colocamos los encabezados de la tabla, la segunda parte de este código está determinada por una consulta sql y en el for lo que hacemos es reemplazar %s por el resultado de la consulta (bueno, estoy tratando de explicar de la forma más sencilla posible!!).

Guarda y ejecuta el programa. Al ejecutar el programa espera algo así como unos tres o cuatro segundos y se abrirá el navegador con el resultado de la consulta que aparece enmarcado dentro de una tabla.

Si todo va bien hasta ahora entonces podemos pasar a crear el reporte en pdf.

Lo primero es descargarnos la última versión del ReportLab que al día de escribir este tutorial anda por la 2.2, se puede descargar de http://www.reportlab.org/

ReportLab trae un binario denominado ReportLab-2.2.win32-py2.5.exe el cual una vez descargado no es sino dar doble clic y seguir las instrucciones de instalación (siguiente, siguiente,.... y listo).

Para verificar si quedó correctamente instalado el pdf puedes hacer la prueba desde la consola de windows como se muestra en la imagen:

Si no te aparece ningún error es porque todo marcha bien.

- Creamos una función para programar el pdf.
- Buscamos la función y allí escribimos

En la parte superior del código agregamos las librerías que vamos a utilizar, en este caso las del reportlab

from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter
from reportlab.lib.units import inch

Luego vamos a la función que hemos creado y allí escribimos lo siguiente:

def genera_pdf(self,event): #init function
#add your code here
sql = c.execute('SELECT * FROM mascotas ORDER BY especie')
res = c.fetchall()

"""Determino la ubicación del reporte, el
tamaño y la orientación del papel a utilizar"""
ca = canvas.Canvas("c:/REPORTES/mascotas.pdf",pagesize=letter)
ca.setFont("Helvetica-Bold",14)
ca.drawString(30,750,"MASCOTAS") #Título
ca.drawString(30,735,u"Ejemplo de Reporte PDF") #Subtítulo

#Defino el tipo y tamaño de la fuente
ca.setFont("Times-Roman",10)
"""Ubico los campos factura y fecha
consultados de la base de datos"""
ca.drawString(30,655,u"Código")
ca.drawString(65,655,"Nombres")
ca.drawString(150,655,"Familia")
ca.drawString(230,655,"Especie")
ca.drawString(280,655,"Sexo")
ca.drawString(310,655,"F. Nacimiento")
ca.drawString(380,655,"F. Muerte")

y = 655

col1 = 30
col2 = 95
col3 = 315
col4 = 425

for i in res:
y = y - 10
y1 = y - 1

codigo = str(i[0])
nombres = str(i[1])
familia = str(i[2])
especie = str(i[3])
sexo = str(i[4])
nace = str(i[5])
muere = str(i[6])


ca.drawString(col1,y,codigo)
ca.line(30,y1,225,y1) #Dibuja la linea (x1,y1,x2,y2)

ca.drawString(65,y,nombres)
ca.line(65,y1,225,y1)

ca.drawString(150,y,familia)
ca.line(150,y1,225,y1)

ca.drawString(230,y,especie)
ca.line(230,y1,225,y1)

ca.drawString(280,y,sexo)
ca.line(280,y1,225,y1)

ca.drawString(310,y,nace)
ca.line(310,y1,225,y1)

ca.drawString(380,y,muere)
ca.line(430,y1,225,y1)

ca.showPage()
ca.save()

os.system('c:/REPORTES/mascotas.pdf') #Muestra el pdf

return #end function

Ejecuta el programa y prueba a generar el pdf, debes obtener algo como esto:

Intenta cambiar los valores de las variables del reportlab para que te des cuenta como funcionan, sino, igual adjunto un archivo en pdf que encontre hace ya muchos días en www.linux-magazine.es con un pequeño pero buen tutorial sobre el manejo de reportlab.

lunes, 10 de noviembre de 2008

Lección No. 7

3 comentarios
Hoy retomaremos la lección 6, la cual complementaremos con nuevos elementos que estudiaremos como las grillas, los estilos/comportamientos y mejoraremos el aspecto del menú.

Materiales para esta lección
No podemos hacer esta lección si no tenemos los materiales de la lección 6 ya trabajados, además de esto necesitaremos:

– 3 iconos de 16x16


Abramos entonces nuevamente la carpeta donde se encuentra el proyecto anterior en mi caso denominada leccion6.

Empecemos por hacer algunas cosas que olvide en la lección pasada como es el darle funcionalidad a la opción Terminar del menú principal.

– Doble clic en el form MyFrame
– Clic en la pestaña Menu

– Clic en la opción Terminar
– Clic en la Events
– Clic en Component Event (botón E)

En el evento EVT_MENU asignamos un nombre a la función, yo le he puesto full_salida.


– Clic en la ficha Python (si estaba seleccionada esta ficha, debes entonces dar clic en la ficha Design y luego nuevamente en la ficha Python con el fin de que actualice el código sino, no podrás encontrar la función que estamos creando).
– Buscamos la función que acabamos de crear (full_salida)
– Y escribimos:

def full_salida(self,event): #init function

#add your code here
self.Close()

return #end function


Ahora ya podemos salir del programa al hacer clic en el menú Terminar.


Qué tal si le mejoramos la apariencia al menú colocando unos cuanto iconos.

En la ficha Menu, seleccionamos el primer ítem del menú denominado mascotas, luego en la ficha Properties buscamos la opción Bitmap; doble clic en esta opción.

Nos debe mostrar la siguiente ventana:


Hacemos clic en el botón RES, el cual nos muestra otra ventana:


En esta ventana debemos elegir el tipo de archivo que vamos a utilizar (Bmp, Jpg, Png, etc) y luego, debajo de la palabra Type existe un botón identificado con tres puntos seguidos … debes hacer clic ahí y localizar el archivo.

Una vez lo tengas localizado tendrás algo parecido a esto:


Haces clic en el botón OK, que te regresa a la ventana anterior y donde también debemos hacer clic en el botón OK. Guardas los cambios y ejecutas el programa para comprobar que hay un icono en nuestro menú de mascotas.

Repetimos los mismos pasos para el menú Terminar, obviamente seleccionando la imagen adecuada para este ítem.

Entonces debemos tener algo similar a esto:


Me imagino que repasaste algo de la lección si no es así es hora de que lo hagas ya que necesitamos crear un ítem de menú entre la opción Mascotas y Terminar denominada Lista Mascotas con su respectivo icono.

El resultado debe ser algo parecido a esto:


Ahora vamos a crear un form para Lista Mascotas al cual denominaremos frm_listar.


Nos volcamos a la ficha Project, hacemos clic con el botón derecho del mouse sobre la carpeta Design el cual nos mostrará un menú flotante en el cual debemos señalar la opción ADD wxMDIChildframe que se encuentra dentro de Add File|frame|panel; pues lo que vamos a crear es un form con la propiedad MDIChild (hija del frame principal MyFrame)
.



Al seleccionar esta opción se debe mostrar el form en la ventana de diseño, cambiemos su aspecto y fuente, y en la propiedad Name la cambiamos por frm_listar nombre con el que debe ser también guardado.

No olvidemos también asignar el título, cambiar el tamaño, etc.


Una vez “organizado” este form vamos a la ficha Components y ubicamos los siguientes componentes guiándonos en la gráfica:


Vamos a cambiar la propiedad de los static text a static text de sólo lectura.

Clic en el primer statictext, luego doble clic en Style de la ficha Properties, nos aparecerá la siguiente ventana:


En esta ventana se adicionan o se cambian algunos “estilos” (yo prefiero llamarlos comportamientos) de controles, formularios, entre otros. Si detallas bien, hacia abajo se encuentra entre otras la opción wxTE_READONLY, seleccionala, clic en aceptar y luego en Ok (observa que se tiene comportamientos interesantes como el ENTER, TAB, PASSWORD que utilizaremos más adelante en otros tutoriales).

Repite lo anterior con los otros dos controles (es posible que no se te pida confirmación de cambio y que solo baste con hacer clic en el botón Ok).

Lo que acabamos de hacer es darle a los controles que actualmente tenemos en el form el “estilo”/comportamiento/propiedad adicional -como lo quieras llamar- de sólo lectura, no podremos cambiar nada de lo que allí se muestre, ni tampoco escribir en estos controles.

Ahora haremos que nuestro form se pueda activar al hacer clic en el menú Lista Mascotas o haciendo clic con la combinación de teclas.

Si no recuerdas como se hace te recomiendo que leas nuevamente la lección anterior (que si que eres desobediente!!), no olvides importarlo en la sección de los includes, allá, arriba del código.


Aprovechamos también y hacemos el código del botón cerrar.


Ahora nos concentraremos en la grilla; vamos a agregar un wxGrid (grilla) que se llenará con algunos de los datos que contiene la tabla mascotas.


En la pestaña Components localizamos una carpeta denominada List que contiene entre otros componentes el que necesitamos, el Grid.

Hacemos doble clic en éste y verificamos que nos aparezca un pequeño recuadro café en la parte superior izquierda de nuestro form.


Para ubicarlo en el lugar que deseamos debemos hacer clic en el control identificado por gr seguido de un número de la pestaña Project del form frm_listar. Una vez seleccionado en esta sección podremos ubicar nuestro grid en el espacio que hemos dejado entre los controles y el botón cerrar.

Le cambiamos su ancho y alto y en la propiedad Name de la ficha Properties cambiamos su nombre a por ejemplo grilla.

Esto es lo que debemos tener hasta el momento.


Cambiamos la propiedad visible a False, agregamos un nuevo botón al que denominaremos bt_listar.

Debemos tener algo parecido a esto:

Creamos la función para el botón bt_listar (una función denominada por ejemplo llenar_grilla) y allí digitamos:
def llenar_grilla(self,event): #init function

#add your code here

sql1 = c.execute('SELECT COUNT(id) FROM mascotas')

res1 = c.fetchall()

rex1 = int(c.rowcount)

sql2 = c.execute('SELECT id,nombres,familia FROM mascotas')
res2 = c.fetchall()
rexx = int(c.rowcount)


#Limpiamos la grilla

self.grilla.Show(True)

self.grilla.ClearGrid()

""" Definimos (filas,columnas),
mediante este for
y la consulta sql1, res1
calculamos el número
de filas
que vamos a utilizar
"""

y = 0
for a in res1:
self.grilla.CreateGrid(a[0],3)
y+=1

#Se le da nombre a los encabezados de las columnas
#y luego se define el tamaño inicial de las columnas

#aunque más abajo se define AutoSizeColumns

self.grilla.SetColLabelValue(0,'CODIGO')

self.grilla.SetColLabelValue(1,'MASCOTA')

self.grilla.SetColLabelValue(2,'FAMILIA')
#Se muestran los resultados de la consulta

x = 0

for i in res2:

self.grilla.SetCellValue(x,0,str(i[0]))

self.grilla.SetCellValue(x,1,str(i[1]))

self.grilla.SetCellValue(x,2,str(i[2]))

self.grilla.AutoSizeColumns(True)

x+=1 self.bt_listar.Enable(False)
#Para evitar llamar nuevamente la grilla

return #end function

Si ejecutamos el programa podemos obtener algo como esto:



O un listado más completo, todo depende de cuántos registros tengas en la base de datos.

Ahora vamos a crear una función que al hacer clic en una de las celdas capture los datos y los ubique en los static_text.


Hacemos clic en la grilla, luego nos vamos a la ficha Events y buscamos el evento EVT_GRID_CELL_LEFT_DCLICK (el 3 de arriba hacia abajo), le damos el nombre a la función (por ejemplo obtiene_datos) y digitamos lo siguiente:

def obtiene_datos(self,event): #init function

#add your code here

"""Se obtienen los datos de la fila seleccionada en la grilla,
esto puedes servir
para eliminar datos, actualizar, etc"""
pos1 = self.grilla.GetCellValue(self.grilla.GetGridCursorRow(),0) #codigo

pos2 = self.grilla.GetCellValue(self.grilla.GetGridCursorRow(),1) #nombre
pos3 = self.grilla.GetCellValue(self.grilla.GetGridCursorRow(),2) #familia
self.txt_codigo.SetLabel(str(pos1))

self.txt_nombre.SetLabel(str(pos2))
self.txt_familia.SetLabel(str(pos3))
return #end function

Ahora cuando tengas datos listados en la grilla y hagas doble clic en una de las celdas, su contenido se visualizará también en los static_text.

Bueno, creo que eso es todo por hoy. Personalmente me gustaría que alguien que tenga buena experiencia en el trabajo con grillas escribiera un pequeño tutorial donde enseñara a editar, actualizar, eliminar, entre otras cosas; lo aquí visto con la grilla es algo realmente básico.

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.

jueves, 11 de septiembre de 2008

Lección No. 5

2 comentarios
Antes que nada... perdón por la demora.

Con la lección de hoy aprenderemos cómo conectarnos a MySQL desde python y cómo hacer algunas acciones básicas de las bases de datos: guardar, buscar, eliminar, actualizar. Todo ello utilizando Python MySQL y VisualWx.


Material de trabajo para esta lección
Para la lección de hoy vamos a necesitar instalar un servidor de MySQL, para ello puedes descargar el AppServ para windows que además te instala el Apache y el Php (claro que eso no los necesitamos pero.... pues matas varios pájaros de un solo tiro), lo puedes encontrar en http://www.appservnetwork.com/index.php?newlang=spanish actualmente yo utilizo la versión 2.5.8. porque la descargue hace mucho tiempo y me ha funcionado sin problemas, pero si ves la página notarás que van en la versión 2.6, ten cuidado con la vesión que descargues ya que tiene que ser compatible con la API que ofrece python para MySQL; Descargalo y cuando lo estés instalando asegurate de asignar una clave al MySQL.

También necesitamos el MySQL-python que lo puedes encontrar en http://sourceforge.net/projects/mysql-python/ descargas e instalas sin mayores inconvenientes (siguiente, siguiente...)

Si sabes pocon pocon de bases de datos, te recomendaría que te descargues también el HeidiSQL de http://www.heidisql.com/ que es un GUI gratis que te permitirá crear tablas, editarlas, etc. y hasta aprender algunas cosas de bdd. Actualmentemente va por la versión 3.2


Manos a la obra
Con estas herramientas ya instaladas procederemos con la lección de hoy, que inicialmente será algo sencillo pero que en las próximas lecciones iremos enriqueciendo.

Lo primero es lo primero, para quienes no sepan qué es MySQL (aunque si estás aquí me imagino que alguito debes saber) en resumidas cuentas podemos decir que es un sistema de gestión de bases de datos similar al SQLite, Postgress, Oracle, entre otros cada uno con sus pequeñas diferencias, sus pro y sus contra, puedes encontrar más documentación en san google.

El archivo MySQL-python-1.2.2.win32-py2.5 (o similar) sera el que nos permita hacer el “enlace” o conexión desde Python con la bdd (base de datos).

Vamos a crear nuestra base de datos y luego la utilizaremos desde VisualWx; si bajaste el HeidiSQL, lo abres, configuras la conexión con la base de datos MySQL (con la clave que le has puesto al instalar el AppServ).


Ya dentro del programa vamos a crear una base de datos denominada afiliados. Para crearla desde el HeidiSQL solo basta con hacer clic derecho en root@localhost seleccionar create database.... y seguir las instrucciones:


Ahora crearemos la tabla para la base de datos afiliados. Lo podemos hacer de varias formas, explicare solo dos, desde HeidiSQL y desde consola:

HeidiSQL
Teniendo seleccionada la base de datos afiliados da clic en el menú tools y de este menú selecciona Create Table, luego ingresa los diferentes campos con sus propiedades, algo como esto:

No olvides cambiar el tipo de dato y su longitud. Por último clic en el botón Create!

Si no te has descargado el Heidi, entonces desde consola se hace así:
Clic en Inicio – Ejecutar – cmd y Enter

Estando en el prompt de win2 digitas: mysql -u root -p y presionas enter.
Se te pedirá la clave que es la que digitaste cuando estabas instalando el AppServ.

Una vez ingreses digitas lo siguiente:

mysql>use afiliados;

Lo anterior es para usar la base de datos afiliados. Ahora a crear la tabla. Digita:

CREATE TABLE personas(
doc INT (11) UNSIGNED NOT NULL, nombre1 VARCHAR (12) NOT NULL,
nombre2 VARCHAR (12), apellido1 VARCHAR (12) NOT NULL,
apellido2 VARCHAR (12), direccion VARCHAR (35) NOT NULL,
telefono VARCHAR (11));

Ya tenemos nuestra base de datos creada (afiliados) con una tabla definida (personas).

Como este no es un tutorial de MySQL deberás buscar en san google si quiere aprender más sobre este sistema de bases de datos.

Ahora abrimos nuestro VisualWx y creamos una nueva aplicación WX_SDI_PYTHON, la guardas en una carpeta con el nombre que quieras (yo le he puesto afiliaciones -que imaginación la mía-).

Le cambiamos el color al form, el tamaño de la fuente; en la propiedad Title: Control de afiliados con MySQL o lo que quieras colocar.

NOTA
Debido a un lapsus mental se me ha ido el título de la ventana "Control de afiliados con SQLite", pero en realidad debería decir "Control de afiliados con MySQL".

Ahora vamos a ubicar los controles para obtener algo como esto:


Esta es la lista de los controles con sus nombres:

Antes de programar conectándonos a la bdd sería bueno programar los focos de los controles. Para iniciar podemos seleccionar el txt_doc y el ficha propiedades cambiar Focus a true, eso hará que cuando se active el form, el foco inicie en este control.

Ahora haremos que cuando se presione cualquiera de las teclas enter/intro o la tecla tab, se cambie el foco al siguiente control.

Mi primer control (documento) se denomina txt_doc y le sigue txt_nombre1, para programar esta acción estando ubicado el txt_doc hago clic en la ficha events y busco el EVT_KEY_DOWN, le doy el nombre a la función y luego en la ficha Python que se encuentra debajo del Form busco la función (yo le he puesto va_n1) y digito lo siguiente:

def va_n1(self,event): #init function
#add your code here
key = event.GetKeyCode()

if key==9 or key==13 or key==wx.WXK_NUMPAD_ENTER:
self.txt_nombre1.SetFocus()

event.Skip()

return #end function

Lo misma forma debes proceder con cada uno de los controles teniendo en cuenta a qué control debe llegar el foco.
Ejecuta el programa (F5) y verifica que todos los focus estén funcionando correctamente.

Si todo anda bien, entonces procedamos con la programación de la base de datos (bdd) y los botones.

Para conectarnos a la base de datos en la parte superior de nuestro código vamos a digitar lo siguiente:

import MySQLdb as con
db = con.connect(host='localhost', user='root', passwd='tuclave', db='afiliados')
c = db.cursor()

Esto importa el MySQL al que denominamos con y luego nos permite hacer la conexión con nuestra bdd denominada afiliados.



Ahora vamos a programar el botón guardar.

Clic en el botón guardar.
Clic en la ficha events.
Clic en el botón E (Component Events)
Clic en el EVT_BUTTON
Dale el nombre a la función, yo le he puesto guarda_datos (sigo impresionado con mi imaginación para asignar nombres!!!)

Vamos a la ficha Python (si la del centro) y buscamos la función que acabamos de crear; allí escribimos lo siguiente:

def guarda_datos(self,event): #init function
#add your code here
doc = self.txt_doc.GetValue()
n1 = self.txt_nombre1.GetValue()
n2 = self.txt_nombre2.GetValue()
ap1 = self.txt_apellido1.GetValue()
ap2 = self.txt_apellido2.GetValue()
di = self.txt_direccion.GetValue()
te = self.txt_telefono.GetValue()

"""Vamos a poner una pequeña restricción que obligue
al usuario a escribir por lo menos el doc, el nombre1
apellido1 y la direccion"""

if doc<>'' and n1<>'' and ap1<>'' and di<>'':
sql = c.execute('INSERT INTO personas VALUES(%s,%s,%s,%s,%s,%s,%s)',
(doc,n1,n2,ap1,ap2,di,te))
res = c.fetchall()

if res<>None:
w=wx.MessageDialog(self,u"Registro almacenado con éxito","REGISTRO",wx.OK | wx.ICON_INFORMATION)
w.ShowModal()
w.Centre()
w.Destroy

self.txt_nombre1.SetLabel('')
self.txt_nombre2.SetLabel('')
self.txt_apellido1.SetLabel('')
self.txt_apellido2.SetLabel('')
self.txt_direccion.SetLabel('')
self.txt_telefono.SetLabel('')

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

self.txt_doc.SetFocus()

return #end function

No olvide los tabulados (identaciones) por favor....

Probamos ejecutando el programa e ingresando cualquier dato para guardarlo utilizando el botón, puede ser nuestro nombre:


El siguiente código puede ser utilizado para diferentes cosas, principalmente para evitar registros duplicados o para localizar rapidamente la información.

Selecciona el txt_doc y en la ficha events localiza el EVT_KILL_FOCUS asignale un nombre a la función, yo le he puesto consulta_datos. Esta función hace que una vez el control txt_doc pierda el foco se active el código de dicha función. Si lo prefieres puedes no utilizar este evento sino el de EVT_SET_FOCUS del control txt_nombre1 el cual recibe el foco después del txt_doc.

Si ya definiste el nombre de la función vamos a copiar el siguiente código:

def consulta_datos(self,event): #init function
#add your code here
doc = self.txt_doc.GetValue()

sql = c.execute('SELECT * FROM personas WHERE doc=%s',(doc))
res = c.fetchall()

if res<>None:
for i in res:
self.txt_nombre1.SetLabel(str(i[1]))
self.txt_nombre2.SetLabel(str(i[2]))
self.txt_apellido1.SetLabel(str(i[3]))
self.txt_apellido2.SetLabel(str(i[4]))
self.txt_direccion.SetLabel(str(i[5]))
self.txt_telefono.SetLabel(str(i[6]))

event.Skip()

return #end function

A grandes rasgos:

doc = self.txt_doc.GetValue() toma el valor del control y lo almacena en la variable doc.

sql = c.execute('SELECT * FROM personas WHERE doc=%s',(doc))
Genera la consulta sql reemplanzando %s por el contenido de la variable doc

res = c.fetchall()
El resultado de la consulta (número de filas devueltas)

if res<>None:
Si el resultado es diferente de vacío.

for i in res:
Se toma la variable i hasta res y se ....

self.txt_nombre1.SetLabel(str(i[1]))
... coloca el valor de cada i[X] en el respectivo control.

A veces ni yo mismo me entiendo per sí sé lo que digo!!! Si hay alguien más que pueda explicar de otra forma más clara o sencilla bienvenido sea.

Qué quiere decir todo esto... que si ejecutas el programa y vuelves a escribir un documento de identidad que YA EXISTE en la base de datos éste (la función) recupera/carga inmediatamente los datos en el form. Uff!!


El código para el botón buscar:
Haces clic en el botón buscar, luego vas a la ficha events, botón E, localizas el EVT_BUTTON, le das un nombre a la función, yo le he puesto.... buscar (qué imaginación) y escribes el siguiente código:

doc = self.txt_doc.GetValue()

sql = c.execute('SELECT * FROM personas WHERE doc=%s',(doc))
res = c.fetchall()

if res<>None:
for i in res:
self.txt_nombre1.SetLabel(str(i[1]))
self.txt_nombre2.SetLabel(str(i[2]))
self.txt_apellido1.SetLabel(str(i[3]))
self.txt_apellido2.SetLabel(str(i[4]))
self.txt_direccion.SetLabel(str(i[5]))
self.txt_telefono.SetLabel(str(i[6]))

event.Skip()

El código para el botón actualizar:
Hacemos el procedimiento como en el botón anterior; yo le he puesto actualiza_datos a la función y el código es el siguiente:

def actualiza_datos(self,event): #init function
#add your code here
doc = self.txt_doc.GetValue()
n1 = self.txt_nombre1.GetValue()
n2 = self.txt_nombre2.GetValue()
ap1 = self.txt_apellido1.GetValue()
ap2 = self.txt_apellido2.GetValue()
di = self.txt_direccion.GetValue()
te = self.txt_telefono.GetValue()

"""Se supone en este ejercicio que podemos actualizar
todos los datos menos el doc de identidad, para poder
cambiar el doc de identidad lo ideal sería haber creado
un indice o campo autonumeríco en la tabla personas"""
sql = c.execute('UPDATE personas SET nombre1=%s,nombre2=%s, \
apellido1=%s,apellido2=%s,direccion=%s,telefono=%s \
WHERE doc=%s',(doc,n1,n2,ap1,ap2,di,te,doc))
res = c.fetchall()

w = wx.MessageDialog(self,u"Registro actualizado con éxito",u"ACTUALIZACIÓN",wx.OK | wx.ICON_INFORMATION )
w.ShowModal()
w.Centre()
w.Destroy()

#Preparamos el form para más datos
self.txt_doc.SetLabel('')
self.txt_nombre1.SetLabel('')
self.txt_nombre2.SetLabel('')
self.txt_apellido1.SetLabel('')
self.txt_apellido2.SetLabel('')
self.txt_direccion.SetLabel('')
self.txt_telefono.SetLabel('')

self.txt_doc.SetFocus()

return #end function


El código para el botón eliminar:
def elimina_datos(self,event): #init function
#add your code here
doc = self.txt_doc.GetValue()

sql = c.execute('DELETE FROM personas WHERE doc=%s',(doc))
res = c.fetchall()

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

self.txt_nombre1.SetLabel('')
self.txt_nombre2.SetLabel('')
self.txt_apellido1.SetLabel('')
self.txt_apellido2.SetLabel('')
self.txt_direccion.SetLabel('')
self.txt_telefono.SetLabel('')

self.txt_doc.SetFocus()

return #end function

Y el código para el botón cerrar:
self.Close()

Obviamente estos códigos son algo “simples” ya que se debería programar teniendo en cuenta algunas restricciones o situaciones en ciertos momentos como lo es por ejemplo al momento de eliminar datos, sin embargo estos pequeños código servirán como ilustración para hacer otras cosas de mayor importancia.

Eso es todo por ahora.

martes, 26 de agosto de 2008

Lección 4

0 comentarios
En esta lección crearemos un mini editor super básico que nos permitirá crear archivos y almacenarlos en cualquier lugar así como recuperarlos.

Utilizaremos los controles Edit text MultiLinea y ToolBar y ToolBar tool. Aprenderemos como cargar imágenes utilizando el editor GUI de VisualWx.

Para esta lección vamos a necesitar 4 iconos o imágenes de 16x16 que nos representen las siguientes acciones: nuevo, abrir, guardar y cerrar.

Crea una carpeta para esta lección y dentro de ella crea otra para almacenar los iconos.

Comenzaremos por crear un form al que pondremos por título “Mi Editor”. Si deseas le cambias el color, yo lo hice.

Vamos a ubicar la barra de herramientas. De la ficha Components seleccionamos la carpeta ToolBar allí se encuentra un control con el mismo nombre “ToolBar”, doble clic para que se ubique en el form.

Seleccionalo y cambiale el nombre a tb_herramientas.

Teniendo seleccionada la barra de herramientas agregamos el control denominado ToolBar Tool que mostrará un pequeño cuadro en dicha barra.

A este tipo de control sólo se le pueden hacer dos cosas desde el editor: cargar la imágen y asignarle el tooltip. Esto lo llevaremos a cabo desde la ficha Propertis.

Teniendo seleccionado este control, en la ficha propiedades (propertis) hacemos clic en Bitmap Tool, nos mostrará la siguiente imagen:

Teniendo esta ventana activa debemos hacer clic en el botón Res el cual nos arrojará esta ventana

desde la cual podemos elegir el tipo de archivo (imagen) que vamos a utilizar (png, gif, jpg, etc.), para cargar la imagen debemos hacer clic en el botón que aparece con los 3 puntos seguidos ... abrir la ubicación del archivo y seleccionarlo, por último clic en el botón Ok.

Teniendo aún seleccionado este control, en la ficha propiedades asignamos a Tool Tip la palabra Nuevo.

Repetimos las acciones anteriores (colocar el ToolBar Tool, asignar imagen, dar nombre) para los botones de abrir, guardar y cerrar con sus respectivos iconos representativos.

En edición nos debe aparecer algo así:


y ejecutado nos muestra algo parecido a esto:

Ahora asegurate de hacer clic en el form, fuera de la barra de herramientas y de la ficha Components elegimos la carpeta Control y de allí seleccionamos Edit Text MultiLinea la ubicamos de tal forma que nos ocupe todo el form y en la propiedad Name le asignamos el nombre txt_contenido.

Ahora vamos a programar los botones de la barra de herramientas, comenzaremos por el botón nuevo:

Selecciona de la ficha Project el control denominado Tool1c, luego ve a la ficha Events, clic en el botón E y en el evento EVT_TOOL asignamos el siguiente nombre de función crea_nuevo


Buscamos la función y digitamos:

def crea_nuevo(self,event): #init function
#add your code here
self.FileName = None
self.txt_contenido.Clear()
return #end function


Repetimos el procedimiento anterior asignando un nombre para cada función dependiendo el botón. Estos son los códigos de cada botón:

def abre_archivo(self,event): #init function
#add your code here
dlg = wx.FileDialog(self, "Abrir archivo", ".", "", "*.*", wx.OPEN)
try:
if dlg.ShowModal() == wx.ID_OK:
filename = dlg.GetPath()
self.txt_contenido.LoadFile(filename)
self.FileName=filename
self.SetTitle(('Mi Editor - %s') % filename)
finally:
dlg.Destroy()


def guarda_archivo(self,event): #init function
#add your code here
dlg = wx.FileDialog(self, "Guardar como", ".", "", "*.*", wx.SAVE)
try:
if dlg.ShowModal() == wx.ID_OK:
filename = dlg.GetPath()
self.txt_contenido.SaveFile(filename)
self.FileName=filename
self.SetTitle(('Mi Editor - %s') % filename)
finally:
dlg.Destroy()
return #end function


def salir_editor(self,event): #init function
#add your code here
self.Close()
return #end function



Ahora sólo queda probar el programa, ejecutalo y ensaya creando un texto pequeño y guardalo en algún lugar, luego trata de recuperarlo o abre otro archivo.

Y ya está.

Código fuente así como el tutorial lo encuentras aquí.

martes, 19 de agosto de 2008

Lección 3

4 comentarios
En esta lección crearemos un pequeño form que nos pedirá el nombre y la fecha de nacimiento y con estos datos calcularemos la edad y mostraremos un mensaje al pulsar un botón.

Utilizaremos los controles Edit text y Date Picker; igualmente haremos algunos cálculos, repasaremos algo de las lecciones anteriores.


LECCIÓN 3


Para esta lección crearemos una carpeta denominada nombre, igualmente crearemos un nuevo proyecto (File – New Project), seleccionamos WX_SDI_Python y guardamos el proyecto con el nombre de leccion3 dentro de la carpeta nombre.

Cargamos el frame MyFrame haciendo doble clic sobre éste.

Cambiamos su color de fondo, yo le he puesto un amarillo crema y como título de ventana le colocamos Mi lección No. 3.

Hasta el momento todo es repaso de la lección No. 2.

Antes de continuar, si deseamos que todos los controles que ubiquemos en el form tengan el mismo tipo y tamaño de fuente entonces procedemos de la siguiente manera:

Clic en cualquier parte del form
Luego, en la ficha propiedades buscas Font
Doble clic y la cambias por tu fuente preferida y el tamaño que deseas.

Yo he seleccionado Arial,11.

Colocamos en el form un Static Text y en la propiedad Name colocamos st_nombre y en la propiedad Text escribimos Nombre.

De la ficha Components hacemos doble clic en Edit Text, luego en la ficha propiedades y teniendo seleccionado el control que acabamos de ubicar en el form, cambiamos la propiedad Name por txt_nombre. Ampliamos un poco el control hacia la derecha para que nos quepa un nombre completo.

Ahora ubicamos otra etiqueta de texto (Static Text) que diga Fecha de nacimiento.

Para obtener algo como esto:


Ahora de la ficha Components buscamos el control denominado Date Picker, lo ubicamos en el form y le cambiamos la propiedad name a dp_fecnac (recuerda ponerle nombre a los controles que tengan referencia con su función o con su contenido, yo acostumbro a colocar las primeras letras que me indican qué tipo de control es separadas por un guión bajo del nombre que me identifica qué información contendrá o qué acción ejecutará).

Si el control una vez ubicado en el form no te corre con el mouse, selecciona el control de la ficha Project y veras como ahora sí puedes mover el control dentro del form.

Debajo de estos controles ubica un Static Text al que sólo le vas a cambiar la propiedad Name:st_mensaje

Por último ubica un botón (Button) cambia sus propiedades Name: bt_calcular y Text:Calcular Edad

Debes tener en pantalla algo parecido a esto:

Ahora procederemos a la programación.

Lo primero que haremos será que cuando el usuario acceda a nuestro programa el cursor se encuentre en el cuadro de texto Nombre, o sea, activaremos el foco inicial allí.

Esta es bien fácil. Haz clic en el txt_nombre o en el cuadro de texto que tienes frente a la palabra Nombre del form; luego en la ficha propiedades busca la propiedad Focus y cambiala de False a True haciendo doble clic sobre la palabra False. Y eso es todo.

Lo segundo es hacer que cuando el usuario presione la tecla enter el foco cambie al date picker y el nombre ingresado quede todo en mayúsculas.

¿Cómo lo hacemos?

Seleccionemos el cuadro de texto denominado txt_nombre, nos cambiamos a la ficha Events y activamos Base wxWidgets Events o como quien dice, hacemos clic en el botón B.

Activamos el evento EVT_KEY_DOWN (cuando se presione un tecla, normalmente se configura para que sea cuando se presione enter) y le asignamos un nombre a este evento, yo le he puesto va_fecha.

Hacemos clic en la ficha Python (la del centro debajo del form) y buscamos el evento que acabamos de asignar denominado va_fecha allí digitamos lo siguiente:


def va_fecha(self,event): #init function

#add your code here

n = self.txt_nombre.GetValue().upper()

key = event.GetKeyCode()

if (key==9 or key==13 or key==wx.WXK_NUMPAD_ENTER):

if n<>'':

self.txt_nombre.SetLabel(n)

self.dp_fecnac.SetFocus()

else:

dlg = wx.MessageDialog(self,"Debe ingresar el nombre","Faltan Datos",wx.OK | wx.ICON_ERROR)

dlg.ShowModal()

dlg.Destroy()

self.txt_nombre.SetFocus()

event.Skip()

return #end function

¿Qué es lo que acabamos de escribir?

En la línea 64 utilizamos un variable denominada n que nos recoge el valor del txt_nombre mediante el GetValue(), al final se observa upper(), esta palabra reservada es la que permite pasar el texto escrito a MAYÚSCULA.

En la línea 65 le asignamos a la variable key el evento GetKeyCode() que recoge el código -creo que ascii- de la tecla presionada.

En la línea 67 lo que hacemos es decirle a Python que si es presionada la tecla TAB (9) o la tecla ENTER (13) o la tecla ENTER del teclado numérico (wx.WXK_NUMPAD_ENTER) evalúe si la variable n se encuentra vacía n<>''.

Si la línea 68 es verdadera entonces, mediante la línea 69 cambiamos el texto a mayúscula y se cambia el foco al date picker dp_fecnac línea 70.

Si no se cumple la condición de la línea 68 entonces se muestra un mensaje de error y el foco vuelve a quedar en el txt_nombre.

Ahora vamos a programar el botón para que cuando éste sea pulsado nos calcule la edad del usuario.

Hacemos clic en el botón y nos pasamos a la ficha Events.

Seleccionamos Component Events o como quien dice, hacemos clic en el botón E.

Activamos el evento EVT_BUTTON (evento de botón) y le asignamos un nombre a la función, yo le he puesto calcular.

Clic en la pestaña Python y antes de buscar el nombre de la función que acabamos de configurar, debemos importar el módulo que maneja los formatos de tiempo y fecha:

En las primeras líneas debes entonces escribir:

import datetime

Justo en ese espacio, para que al ejecutar el programa no se te desaparezca.

Ahora sí buscamos nuestra función “calcular” y allí vamos a escribir:

def calcular(self,event): #init function

#add your code here

n = self.txt_nombre.GetValue()

fnace = self.dp_fecnac.GetValue().Format('%Y/%m/%d')

anio = fnace[:4]

mes = fnace[5:7]

dia = fnace[8:10]

nacim=datetime.date(int(anio),int(mes),int(dia))

dhoy=datetime.date.today()


edad=dhoy.year-nacim.year

if nacim.replace(year=dhoy.year):

edad -=1

e = edad+1

x = str(e)

self.st_mensaje.SetLabel(u'%s tu edad es de: %s años' % (n,x))

return #end function


Pero qué rayos es todo este cuento!!!

En la línea 52 tenemos una variable n que nos recoge el valor del txt_nombre

En la línea 53 tenemos una variable fnace que nos almacena la fecha ingresada (se supone que la de nacimiento) seguida por Format('%Y/%m/%d') que hace que la fecha ingresada quede con el formato de 4 dígitos en la fecha, dos en el mes y dos en el día, ejemplo: 1976/05/26, bueno puedes aprender más con la ayuda de Python.

En las líneas del 55 al 57 lo que estamos haciendo es almacenando parte de esa fecha en las variables anio, mes, día; me explico con el siguiente ejemplo:

Seleccione la fecha 1976/05/26; observa que anio tiene [:4] quiere decir que toma los valores que van desde el índice 0 (inclusive) hasta el 3 dígito, o sea, 1976; mes tiene [5:7] va desde el índice 5 (inclusive) hasta el 6 y por último tenemos día que va desde [8:10] aquí hay que agregar un número más a la cadena (10) ya que el operador de corte : ejecuta va hasta el j-1.

Para que tengas un poco más claro este concepto te recomiendo el tutorial Introducción a la programación con python de Andrés Marzal e Isabel Gracia, pág. 167 (Subcadenas: operador de corte). Excelente tutorial, lo que no recuerdo es de dónde me lo baje :(

Así ya recorde http://marmota.act.uji.es/MTP)

Bueno, continuo tratando de explicar (es que a veces yo no me entiendo pero sí sé lo que digo).

En la línea 59 utilizamos la variable nacim para almacenar el formato de fecha del datetime, razón por la cual en las primeras líneas teníamos que importar dicha clase, para poder utilizar sus propiedades más abajo.

Con la variable dhoy ubicada en la línea 60, obtenemos, perdón almacenamos la fecha de hoy en el formato yyyy-mm-dd o yyyy/mm/dd (realmente el separador – o / al final no es que importe mucho).

En la línea 62 con la variable edad lo que estamos haciendo realmente es restar el año actual con el año de la variable nacim o sea, el que ingresamos de nuestra fecha de nacimiento.

En la línea 63 hacemos un reemplazo de variable y una comparación, es para quitarle una unidad (línea 64) a la edad si el año de la edad dada es menor al año actual, sino (línea 65) le agrega una unidad.

En la línea 66 utilizamos una nueva variable x que convierte a la variable e en una cadena de texto para poderla ubicar dentro del st_mensaje.

Por último llega la línea 67 que mostrará el mensaje una vez se cumplan todas anteriores condiciones.

Al ejecutar el programa tenemos algo parecido a esto:

Bueno, eso es todo por hoy.

Mucha suerte a tod@s.

Y sería bueno que colocaran algún comentario quizás eso me anime más.