miércoles, 10 de marzo de 2010

Crear mantenimiento básico con Python y wxPython

Vamos a ver en este post como crear un mantenimiento de clientes, creando, actualizando, insertando y borrando registros de una base de datos MySQL. Como interfaz, utilizaremos wxPython, y como lenguaje, Python (¡sorpresa!).

Lo primero es crear la interfaz. Para ello utilizamos wxGlade. Hace tiempo escribí un post de cómo crear aplicaciones en este diseñador de pantallas, así que aquí pongo una captura de cómo es la pantalla, y a continuación el código que genera wxGlade, el cual he modificado (variables a1, a2, a3 ...) para poder llamar a los manejadores de eventos correspondientes.. Los iconos del frame los he buscado en Internet, ya que no vienen en ninguna distribución de wxGlade. Quedaría así:


El funcionamiento es muy simple. Están los típicos botones de crear, eliminar, borrar y guardar cliente. Además, mediante los botones de flechas (azules) se puede navegar a través de la tabla de clientes.

El código que genera wxGlade (y que he modificado) lo he guardado en el fichero cliente_frame.py, y es el siguiente:

#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-
# generated by wxGlade 0.6.3 on Tue Mar 09 23:59:26 2010

import wx

# begin wxGlade: extracode
# end wxGlade



class MyFrame(wx.Frame):
def __init__(self, *args, **kwds):
# begin wxGlade: MyFrame.__init__
kwds["style"] = wx.DEFAULT_FRAME_STYLE
wx.Frame.__init__(self, *args, **kwds)
self.panel = wx.Panel(self, -1)

# Menu Bar
self.barra_menu = wx.MenuBar()
self.SetMenuBar(self.barra_menu)
# Menu Bar end
self.barra_estado = self.CreateStatusBar(1, wx.ST_SIZEGRIP)

# Tool Bar
self.barra_herramientas = wx.ToolBar(self, -1)
self.SetToolBar(self.barra_herramientas)
a1 = self.barra_herramientas.AddLabelTool(wx.NewId(), "nuevo", \
wx.Bitmap("d:\\python\\iconos\\on\\filenew.gif", wx.BITMAP_TYPE_ANY) \
, wx.NullBitmap, wx.ITEM_NORMAL, "Nuevo", "Crear nuevo cliente")
a2 = self.barra_herramientas.AddLabelTool(wx.NewId(), "guardar", \
wx.Bitmap("d:\\python\\iconos\\on\\filesave.gif", wx.BITMAP_TYPE_ANY)\
, wx.Bitmap("d:\\python\\iconos\\off\\filesave.gif", wx.BITMAP_TYPE_ANY), \
wx.ITEM_NORMAL, "Guardar", "Guardar cliente en base de datos")
a3 = self.barra_herramientas.AddLabelTool(wx.NewId(), "cancelar", \
wx.Bitmap("d:\\python\\iconos\\on\\cancel.gif", wx.BITMAP_TYPE_ANY) \
, wx.Bitmap("d:\\python\\iconos\\off\\cancel.gif", wx.BITMAP_TYPE_ANY),\
wx.ITEM_NORMAL, "Cancelar", "Cancelar operación")
a4 = self.barra_herramientas.AddLabelTool(wx.NewId(), "editar", \
wx.Bitmap("d:\\python\\iconos\\on\\edit.gif", wx.BITMAP_TYPE_ANY)\
, wx.Bitmap("d:\\python\\iconos\\off\\edit.gif", wx.BITMAP_TYPE_ANY),\
wx.ITEM_NORMAL, "Editar", "Editar cliente actual")
a5 = self.barra_herramientas.AddLabelTool(wx.NewId(), "buscar",\
wx.Bitmap("d:\\python\\iconos\\on\\find.gif", wx.BITMAP_TYPE_ANY)\
, wx.Bitmap("d:\\python\\iconos\\off\\find.gif", wx.BITMAP_TYPE_ANY),\
wx.ITEM_NORMAL, "Buscar", "Buscar cliente en base de datos")
a6 = self.barra_herramientas.AddLabelTool(wx.NewId(), "eliminar", \
wx.Bitmap("d:\\python\\iconos\\on\\remove.gif", wx.BITMAP_TYPE_ANY)\
, wx.Bitmap("d:\\python\\iconos\\off\\remove.gif", wx.BITMAP_TYPE_ANY),\
wx.ITEM_NORMAL, "Eliminar", "Eliminar cliente de base de datos")
a7 = self.barra_herramientas.AddLabelTool(wx.NewId(), "recargar", \
wx.Bitmap("d:\\python\\iconos\\on\\reload.gif", wx.BITMAP_TYPE_ANY)\
, wx.Bitmap("d:\\python\\iconos\\off\\reload.gif", wx.BITMAP_TYPE_ANY),\
wx.ITEM_NORMAL, "Recargar", "Recargar información de cliente")
a8 = self.barra_herramientas.AddLabelTool(wx.NewId(), "izda_final",\
wx.Bitmap("d:\\python\\iconos\\on\\player_start.gif", wx.BITMAP_TYPE_ANY)\
, wx.Bitmap("d:\\python\\iconos\\off\\player_start.gif", wx.BITMAP_TYPE_ANY),\
wx.ITEM_NORMAL, "Inicio", "Primer registro")
a9 = self.barra_herramientas.AddLabelTool(wx.NewId(), "izda_rapido", \
wx.Bitmap("d:\\python\\iconos\\on\\2leftarrow.gif", wx.BITMAP_TYPE_ANY)\
, wx.Bitmap("d:\\python\\iconos\\off\\2leftarrow.gif",\
wx.BITMAP_TYPE_ANY), wx.ITEM_NORMAL, u"Avance rápido",\
u"Avance rápido de registros a la izquierda")
a10 = self.barra_herramientas.AddLabelTool(wx.NewId(), "izda", \
wx.Bitmap("d:\\python\\iconos\\on\\1leftarrow.gif", wx.BITMAP_TYPE_ANY)\
, wx.Bitmap("d:\\python\\iconos\\off\\1leftarrow.gif", wx.BITMAP_TYPE_ANY), \
wx.ITEM_NORMAL, "Izquierda", "Avance de un registro a la izquierda")
a11 = self.barra_herramientas.AddLabelTool(wx.NewId(), "drcha", \
wx.Bitmap("d:\\python\\iconos\\on\\1rightarrow.gif", wx.BITMAP_TYPE_ANY)\
, wx.Bitmap("d:\\python\\iconos\\off\\1rightarrow.gif", wx.BITMAP_TYPE_ANY),\
wx.ITEM_NORMAL, "Derecha", "Avance de un registro a la derecha")
a12 = self.barra_herramientas.AddLabelTool(wx.NewId(), "drcha_rapido", \
wx.Bitmap("d:\\python\\iconos\\on\\2rightarrow.gif", wx.BITMAP_TYPE_ANY),\
wx.Bitmap("d:\\python\\iconos\\off\\2rightarrow.gif", wx.BITMAP_TYPE_ANY), \
wx.ITEM_NORMAL, u"Avance rápido", u"Avance rápido de registros a la derecha")
a13 = self.barra_herramientas.AddLabelTool(wx.NewId(), "drcha_final", \
wx.Bitmap("d:\\python\\iconos\\on\\player_end.gif", wx.BITMAP_TYPE_ANY), \
wx.Bitmap("d:\\python\\iconos\\off\\player_end.gif", wx.BITMAP_TYPE_ANY),\
wx.ITEM_NORMAL, "Final", u"Último registro")
a14 = self.barra_herramientas.AddLabelTool(wx.NewId(), "ayuda", \
wx.Bitmap("d:\\python\\iconos\\on\\help.gif", wx.BITMAP_TYPE_ANY), \
wx.Bitmap("d:\\python\\iconos\\off\\help.gif", wx.BITMAP_TYPE_ANY),\
wx.ITEM_NORMAL, "Ayuda", "Programa clientes escrito en Python, wxPython y MySQL.")
a15 = self.barra_herramientas.AddLabelTool(wx.NewId(), "salir", \
wx.Bitmap("d:\\python\\iconos\\on\\exit.gif", wx.BITMAP_TYPE_ANY), \
wx.Bitmap("d:\\python\\iconos\\off\\exit.gif", wx.BITMAP_TYPE_ANY),\
wx.ITEM_NORMAL, "Salir", "Salir de la aplicación de clientes")
# Tool Bar end
self.label_1 = wx.StaticText(self.panel, -1, "ID")
self.text_ctrl_id = wx.TextCtrl(self.panel, -1, "", style=wx.TE_READONLY)
self.label_2 = wx.StaticText(self.panel, -1, "NOMBRE")
self.text_ctrl_nombre = wx.TextCtrl(self.panel, -1, "")
self.label_3 = wx.StaticText(self.panel, -1, "APELLIDOS")
self.text_ctrl_apellidos = wx.TextCtrl(self.panel, -1, "")
self.label_4 = wx.StaticText(self.panel, -1, "NIF")
self.text_ctrl_nif = wx.TextCtrl(self.panel, -1, "")
self.label_5 = wx.StaticText(self.panel, -1, u"CORREO ELECTRÓNICO")
self.text_ctrl_email = wx.TextCtrl(self.panel, -1, "")
self.label_6 = wx.StaticText(self.panel, -1, u"DIRECCIÓN WEB")
self.text_ctrl_web = wx.TextCtrl(self.panel, -1, "")
self.label_7 = wx.StaticText(self.panel, -1, "OBSERVACIONES")
self.text_ctrl_observ = wx.TextCtrl(self.panel, -1, "", \
style=wx.TE_MULTILINE|wx.HSCROLL)

self.__set_properties()
self.__do_layout()

self.Bind(wx.EVT_TOOL, self.Onnuevo, a1)
self.Bind(wx.EVT_TOOL, self.Onguardar, a2)
self.Bind(wx.EVT_TOOL, self.Oncancelar, a3)
self.Bind(wx.EVT_TOOL, self.Oneditar, a4)
self.Bind(wx.EVT_TOOL, self.Onbuscar, a5)
self.Bind(wx.EVT_TOOL, self.Oneliminar, a6)
self.Bind(wx.EVT_TOOL, self.Onrecargar, a7)
self.Bind(wx.EVT_TOOL, self.Onizda_final, a8)
self.Bind(wx.EVT_TOOL, self.Onizda_rapido, a9)
self.Bind(wx.EVT_TOOL, self.Onizda, a10)
self.Bind(wx.EVT_TOOL, self.Ondrcha, a11)
self.Bind(wx.EVT_TOOL, self.Ondrcha_rapido, a12)
self.Bind(wx.EVT_TOOL, self.Ondrcha_final, a13)
self.Bind(wx.EVT_TOOL, self.Onayuda, a14)
self.Bind(wx.EVT_TOOL, self.Onsalir, a15)
# end wxGlade

def __set_properties(self):
# begin wxGlade: MyFrame.__set_properties
self.SetTitle("Mantenimiento de clientes")
_icon = wx.EmptyIcon()
_icon.CopyFromBitmap(wx.Bitmap("D:\\python\\iconos\\aplicacion\\icon_history.gif", \
wx.BITMAP_TYPE_ANY))
self.SetIcon(_icon)
self.SetSize((436, 386))
self.barra_estado.SetStatusWidths([-1])
# statusbar fields
barra_estado_fields = ["http://elviajedelnavegante.blogspot.com"]
for i in range(len(barra_estado_fields)):
self.barra_estado.SetStatusText(barra_estado_fields[i], i)
self.barra_herramientas.Realize()
self.text_ctrl_id.SetMinSize((250, 20))
self.text_ctrl_nombre.SetMinSize((250, 20))
self.text_ctrl_apellidos.SetMinSize((250, 20))
self.text_ctrl_nif.SetMinSize((250, 20))
self.text_ctrl_email.SetMinSize((250, 20))
self.text_ctrl_web.SetMinSize((250, 20))
self.text_ctrl_observ.SetMinSize((250, 100))
# end wxGlade

def __do_layout(self):
# begin wxGlade: MyFrame.__do_layout
sizer = wx.BoxSizer(wx.VERTICAL)
grid_sizer_1 = wx.FlexGridSizer(7, 2, 0, 0)
grid_sizer_1.Add(self.label_1, 0, 0, 0)
grid_sizer_1.Add(self.text_ctrl_id, 0, 0, 0)
grid_sizer_1.Add(self.label_2, 0, 0, 0)
grid_sizer_1.Add(self.text_ctrl_nombre, 0, 0, 0)
grid_sizer_1.Add(self.label_3, 0, 0, 0)
grid_sizer_1.Add(self.text_ctrl_apellidos, 0, 0, 0)
grid_sizer_1.Add(self.label_4, 0, 0, 0)
grid_sizer_1.Add(self.text_ctrl_nif, 0, 0, 0)
grid_sizer_1.Add(self.label_5, 0, 0, 0)
grid_sizer_1.Add(self.text_ctrl_email, 0, 0, 0)
grid_sizer_1.Add(self.label_6, 0, 0, 0)
grid_sizer_1.Add(self.text_ctrl_web, 0, 0, 0)
grid_sizer_1.Add(self.label_7, 0, 0, 0)
grid_sizer_1.Add(self.text_ctrl_observ, 0, 0, 0)
self.panel.SetSizer(grid_sizer_1)
grid_sizer_1.AddGrowableRow(0)
grid_sizer_1.AddGrowableRow(1)
grid_sizer_1.AddGrowableRow(2)
grid_sizer_1.AddGrowableRow(3)
grid_sizer_1.AddGrowableRow(4)
grid_sizer_1.AddGrowableRow(5)
grid_sizer_1.AddGrowableRow(6)
grid_sizer_1.AddGrowableCol(0)
grid_sizer_1.AddGrowableCol(1)
sizer.Add(self.panel, 1, wx.EXPAND, 0)
self.SetSizer(sizer)
sizer.SetSizeHints(self)
self.Layout()
self.Centre()
# end wxGlade

def Onnuevo(self, event): # wxGlade: MyFrame.
print "Event handler `Onnuevo' not implemented!"
#event.Skip()

def Onguardar(self, event): # wxGlade: MyFrame.
print "Event handler `Onguardar' not implemented!"
event.Skip()

def Oncancelar(self, event): # wxGlade: MyFrame.
print "Event handler `Oncancelar' not implemented!"
event.Skip()

def Oneditar(self, event): # wxGlade: MyFrame.
print "Event handler `Oneditar' not implemented!"
event.Skip()

def Onbuscar(self, event): # wxGlade: MyFrame.
print "Event handler `Onbuscar' not implemented!"
event.Skip()

def Oneliminar(self, event): # wxGlade: MyFrame.
print "Event handler `Oneliminar' not implemented!"
event.Skip()

def Onrecargar(self, event): # wxGlade: MyFrame.
print "Event handler `Onrecargar' not implemented!"
event.Skip()

def Onizda_final(self, event): # wxGlade: MyFrame.
print "Event handler `Onizda_final' not implemented!"
event.Skip()

def Onizda_rapido(self, event): # wxGlade: MyFrame.
print "Event handler `Onizda_rapido' not implemented!"
event.Skip()

def Onizda(self, event): # wxGlade: MyFrame.
print "Event handler `Onizda' not implemented!"
event.Skip()

def Ondrcha(self, event): # wxGlade: MyFrame.
print "Event handler `Ondrcha' not implemented!"
event.Skip()

def Ondrcha_rapido(self, event): # wxGlade: MyFrame.
print "Event handler `Ondrcha_rapido' not implemented!"
event.Skip()

def Ondrcha_final(self, event): # wxGlade: MyFrame.
print "Event handler `Ondrcha_final' not implemented!"
event.Skip()

def Onayuda(self, event): # wxGlade: MyFrame.
print "Event handler `Onayuda' not implemented!"
event.Skip()

def Onsalir(self, event): # wxGlade: MyFrame.
print "Event handler `Onsalir' not implemented!"
event.Skip()

# end of class MyFrame
Podemos cambiar la ruta absoluta de los iconos del frame por rutas relativas, de manera que los iconoslos guardemos en una carpeta de recursos en el directorio en donde se encuentre nuestro fichero ejecutable Python. Nos aseguramos de esta manera que los iconos se encuentren siempre. Así, por ejemplo, para la siguiente línea:

self.barra_herramientas.AddLabelTool(wx.NewId(), "nuevo", wx.Bitmap("d:\\python\\iconos\\on\\filenew.gif", wx.BITMAP_TYPE_ANY), wx.NullBitmap, wx.ITEM_NORMAL, "Nuevo", "Ayuda larga nuevo")

La ruta absoluta del icono filenew.gif la podemos calcular de la siguiente forma:

os.path.realpath("iconos\\on\\filenew.gif")

También podemos hacer:

ruta_aux = "iconos\\"
os.path.realpath(aux_ruta+"on\\filenew.gif")


NOTA: Cuidado si estás programando IDLE y wxPython. No son nada compatibles. Te aconsejo que si utilizas wxPython no escribas nada con IDLE. Resultados inesperados, y cosas muy desagradables, como que se te cierre IDLE inesperadamente sin guardar cambios. Lo digo por experiencia. Yo, en mi caso, voy a utilizar como editor Gedit. Es un editor muy ligero, del proyecto GNOME, para Windows. Reconoce código Python, pintándolo con colores. No lleva completitud. La indentación de código la podemos hacer con el tabulador, que es configurable en espacios.

En esta primera parte tenemos toda la implementación de la vista del programa.

Segunda parte. Se supone que tenemos instalado un servidor MySQL ó el acceso a una máquina con dicho servicio activo.

Lo primero es crear la base de datos:

CREATE DATABASE `cliente_python` ;
Creamos una tabla clientes, de siguiente modo:
CREATE TABLE `cliente` (
`id` BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`nombre` VARCHAR( 50 ) NOT NULL ,
`apellidos` VARCHAR( 50 ) NOT NULL ,
`nif` VARCHAR( 9 ) NOT NULL ,
`email` VARCHAR( 50 ) NOT NULL ,
`web` VARCHAR( 50 ) NOT NULL ,
`observ` VARCHAR( 100 ) NOT NULL
) ENGINE = innodb COMMENT = 'Tablas de clientes';

Ya tenemos la parte de la base de datos. ¿Qué mas necesitamos? El intermediario entre la base de datos y Python. Para ello utilizamos mySQLdb. ¿Cómo instalar mySQLdb en Windows? Para esta plataforma hay un ejecutable que se puede descargar de http://sourceforge.net/projects/mysql-python/files/. En mi caso, que tengo Python 2.5, así que me he bajado el fichero MySQL-python-1.2.2.win32-py2.5.exe.

Una vez instalado, en el intérprete de Python ejecutamos import MySQLdb para ver si efectivamente se ha instalado de forma correcta.

Finalmente, creamos el fichero cliente.py, que será el ejecutable de nuestra aplicación. En él se hereda el frame que hemos descrito anteriormente. Leyendo el código no se debe de tener problemas para su entendimiento. No he implementado ciertas opciones, como la búsqueda, por falta de tiempo. Dejo al lector su desarrollo.

El contenido de cliente.py es el siguiente:

# -*- coding: cp1252 -*-
'''
# Progama de mantenimiento de clientes en una base de datos. Se utiliza wxPython
# para programar la interfaz gráfica y el motor MySQL para guardar datos.
# Plataforma: Windows
# Versión Python: 2.5.4
# Autor: Ángel Luis García García
# Blog: http://elviajedelnavegante.blogspot.com
'''

from cliente_frame import MyFrame
import MySQLdb
import wx

class frame_principal(MyFrame):
def __init__(self, *args, **kwds):
# Llamamos al constructor de la clase de la cual heredamos.
MyFrame.__init__(self, *args, **kwds)
# Creamos conexión con base de datos.
self.conexionMySQL = MySQLdb.connect("localhost", "root", \
"1234","cliente_python")
# Creamos cursor.
self.cursorMySQL = self.conexionMySQL.cursor()
# Nº máximo de registros.
self.__maxfilasMySQL = 0
# Cargamos registros.
self.cargarRegistro(self.cargarFilas())
# ASociamos el salir de la aplicación con su manejador de eventos.
self.Bind(wx.EVT_CLOSE, self.Onsalir)

def Onrecargar(self, event):
self.cargarFilas()

def Onnuevo(self, event): # wxGlade: MyFrame.
'''
Nuevo cliente.
'''
self.limpiarRegistros()

def Onguardar(self, event): # wxGlade: MyFrame.
ret = self.datosRegistro()
'''
Guardamos cliente.
'''
# Primero comprobamos si se trata de una edición. Si existe ID, se está editando, por lo que hay que actualizar.
id_aux = str(ret[0])
if len(id_aux) != 0:
# Actualizamos cliente.
try:
cadenaSQL = "UPDATE `cliente_python`.`cliente` SET `nombre` = %s, `apellidos` = %s, `nif` = %s, \
`email` = %s, `web` = %s, `observ` = %s WHERE `cliente`.`id` = %s ;"
self.cursorMySQL.execute(cadenaSQL, (ret[1], ret[2], ret[3], ret[4], ret[5], ret[6], ret[0]))
self.conexionMySQL.commit()
self.infoBarraEstado('Se actualizó el cliente actual.')
self.cargarFilas()
except:
self.conexionMySQL.rollback()
self.infoBarraEstado('No se pudo actualizar el cliente actual.')
else:
# Insertamos nuevo cliente.
try:
cadenaSQL = "INSERT INTO `cliente_python`.`cliente` (`id` ,`nombre` ," + \
"`apellidos` ,`nif` ,`email` ,`web` ,`observ`) VALUES (" + \
"NULL , %s, %s, %s, %s, %s, %s);"
self.cursorMySQL.execute(cadenaSQL, (ret[1], ret[2], ret[3], ret[4], ret[5], ret[6]))
self.conexionMySQL.commit()
self.infoBarraEstado('Se guardó el nuevo cliente.')
self.cargarFilas()
except:
self.conexionMySQL.rollback()
self.infoBarraEstado('No se pudo guardar al nuevo cliente')

def Oncancelar(self, event): # wxGlade: MyFrame.
self.limpiarRegistros()

def Oneditar(self, event): # wxGlade: MyFrame.
'''
Edición
'''
print "Sin implementar"

def Onbuscar(self, event): # wxGlade: MyFrame.
'''
Búsqueda de registros.
'''
print "Sin implementar"


def Oneliminar(self, event): # wxGlade: MyFrame.
'''
Eliminar el cliente actual.
'''
# Primero se comprueba si hay ID.
ret = self.datosRegistro()
aux = str(ret[0])
if len(aux) == 0:
self.infoBarraEstado('Para eliminar un cliente hay que cargarlo primero.')
return -1
# Hay un cliente.
ret = wx.MessageBox('¿Eliminar cliente?', "Atención", wx.YES_NO)
if ret == wx.NO:
self.infoBarraEstado('Se canceló la eliminación')
if ret == wx.YES:
# Borramos el cliente.
try:
cadenaSQL = 'DELETE FROM `cliente_python`.`cliente` WHERE `id` = %s'
self.cursorMySQL.execute(cadenaSQL, (aux))
self.conexionMySQL.commit()
self.infoBarraEstado('Se eliminó el cliente.')
self.cargarFilas()
except:
self.conexionMySQL.rollback()
self.infoBarraEstado('No se pudo eliminar el cliente')

def Onrecargar(self, event):
self.__maxfilasMySQL = self.cursorMySQL.execute("SELECT * FROM cliente")
self.cursorMySQL.scroll(0)
ret = self.cursorMySQL.fetchone()
self.cargarRegistro(ret)

def Onizda_final(self, event): # wxGlade: MyFrame.
'''
Primer elemento.
'''
self.cursorMySQL.scroll(0,'absolute')
ret = self.cursorMySQL.fetchone()
self.cargarRegistro(ret)

def Onizda_rapido(self, event): # wxGlade: MyFrame.
'''
Desplazamos elemento a la izquierda, de 3 en 3.
'''
try:
self.cursorMySQL.scroll(-5)
ret = self.cursorMySQL.fetchone()
except:
self.cursorMySQL.scroll(0,'absolute')
ret = self.cursorMySQL.fetchone()
self.cargarRegistro(ret)

def Onizda(self, event): # wxGlade: MyFrame.
'''
Desplazamos un elemento a la izquierda.
'''
try:
self.cursorMySQL.scroll(-2)
ret = self.cursorMySQL.fetchone()
except:
self.cursorMySQL.scroll(0,'absolute')
ret = self.cursorMySQL.fetchone()
self.cargarRegistro(ret)

def Ondrcha(self, event): # wxGlade: MyFrame.
'''
Desplazamos un elemento a la derecha
'''
try:
self.cursorMySQL.scroll(0)
ret = self.cursorMySQL.fetchone()
except:
self.cursorMySQL.scroll(self.__maxfilasMySQL - 1,'absolute')
ret = self.cursorMySQL.fetchone()
self.cargarRegistro(ret)

def Ondrcha_rapido(self, event): # wxGlade: MyFrame.
'''
Desplazamos un elemento a la derecha, de 3 en 3.
'''
try:
self.cursorMySQL.scroll(3)
ret = self.cursorMySQL.fetchone()
except:
self.cursorMySQL.scroll(self.__maxfilasMySQL - 1,'absolute')
ret = self.cursorMySQL.fetchone()
self.cargarRegistro(ret)


def Ondrcha_final(self, event): # wxGlade: MyFrame.
'''
Registro final.
'''
self.cursorMySQL.scroll(self.__maxfilasMySQL - 1,'absolute')
ret = self.cursorMySQL.fetchone()
self.cargarRegistro(ret)

def Onayuda(self, event): # wxGlade: MyFrame.
cadena = "Programa de mantenimiento de de clientes."+"\r\n"+\
"Se ha utilizado Python wxPython y MySQL."+"\r\n"+ \
"Escrito por Ángel Luis García García"+"\r\n"+ \
"http://elviajedelnavegante.blogspot.com"
wx.MessageBox(cadena, "Info")

def Onsalir(self, event): # wxGlade: MyFrame.
# Cerramos conexion
self.cursorMySQL.close()
self.conexionMySQL.close()
# Y nos vamos.
self.Destroy()

def cargarFilas(self):
self.__maxfilasMySQL = self.cursorMySQL.execute("SELECT * FROM cliente")
#self.cursorMySQL.scroll(0)
ret = self.cursorMySQL.fetchone()
return ret

def visualizarFila(self):
ret = self.cursorMySQL.fetchone()
return ret

def limpiarRegistros(self):
self.text_ctrl_id.Value = ""
self.text_ctrl_nombre.Value = ""
self.text_ctrl_apellidos.Value = ""
self.text_ctrl_nif.Value = ""
self.text_ctrl_email.Value = ""
self.text_ctrl_web.Value = ""
self.text_ctrl_observ.Value = ""

def datosRegistro(self):
ret = []
ret.append(self.text_ctrl_id.Value)
ret.append(self.text_ctrl_nombre.Value)
ret.append(self.text_ctrl_apellidos.Value)
ret.append(self.text_ctrl_nif.Value)
ret.append(self.text_ctrl_email.Value)
ret.append(self.text_ctrl_web.Value)
ret.append(self.text_ctrl_observ.Value)
return ret

def cargarRegistro(self, ret):
self.text_ctrl_id.Value = str(ret[0])
self.text_ctrl_nombre.Value = str(ret[1])
self.text_ctrl_apellidos.Value = str(ret[2])
self.text_ctrl_nif.Value = str(ret[3])
self.text_ctrl_email.Value = str(ret[4])
self.text_ctrl_web.Value = str(ret[5])
self.text_ctrl_observ.Value = str(ret[6])

def infoBarraEstado(self,texto):
barra_estado_fields = [texto]
for i in range(len(barra_estado_fields)):
self.barra_estado.SetStatusText(barra_estado_fields[i], i)




Espero que esto pueda resultaros de ayuda para introduciros de buen pie en el mundo de Python, wxPython, con MySQL.

Saludos.




3 comentarios:

  1. Hola! Estoy haciendo una aplicación con Python y wxGlade... el problema es que no me funcionan los manejadores de eventos! =S Por ejemplo, tengo un menú con varios botones, al darle click se debería desplegar la ventana correspondiente, pero me devuelve el error 'module' object has no attribute '...' Revisé con tu blog y el código tiene la misma secuencia, así que no sé donde está el error! De antemano gracias por tu ayuda! =)

    ResponderEliminar
  2. Hola. Para poder ayudarte necesito más información. Por favor, envíame tu código a mi email, para ver de que se trata y poder ayudarte, ya que con lo que me dices no se cual es el problema. Necesitaría todo el código. Me lo puedes enviar a angelluis78@gmail.com. Espero tu correo. Saludos.

    ResponderEliminar
  3. exelente blog te enviare un correo por ayuda por favor ... muchas gracias te ante mano

    ResponderEliminar