Uso de mo mo dulos de clase para crear tus propios objetos Traducción libre realizada por: Saúl Rojas (
[email protected] [email protected])) septiembre, 2014. Nota del traductor:
El siguiente material fue extraído de la dirección web: http://www.dimgt.com.au/cl_Simple.html donde se encuentra la versión original en inglés. Me he tomado el atrevimiento de hacer ésta traducción libre debido al aparentemente escaso material circulante en español acerca del uso de módulos de clases en Access. La programación con objetos en Access parece ser ser un asunto aún no explotado explotado en todo su potencial. En base a mi propia experiencia puedo decir que ésta técnica de programación requiere de cierto esfuerzo, sobre todo al comienzo, para dominarla con algo de soltura, pero como bien lo afirma el autor en los párrafos siguientes, “bien vale la pena el esfuerzo”; ¿ por qué? Porque el código es más organizado, más acorde a la realidad, más fácil de leer y corregir, más poderoso y quizás otros “más” que ustedes, apreciados lectores, vislumbraran durante su aprendizaje.
Quiero aclarar que la presente traducción fue realizada, no por un traductor técnico profesional, sino por un entusiasta de la programación en MS Access con algunos rudimentos de la lengua Inglesa. Por lo tanto, cualquier error de traducción es de mi entera responsabilidad. No obstante, siempre está la versión original en inglés la cual pueden consultar si así lo desean. Quiero además aprovechar éstas líneas para expresar una vez más mi perenne agradecimiento a Neckkito (Miquel), a quien considero mi primer y mejor maestro de programación, por haberme abierto los ojos al mundo oculto tras la combinación de teclas Alt + F11. Por cierto, en el Tutorial de VBA de su autoría el cual pueden hallar en su página web: http://siliconproject.com.ar/neckkito específicamente en la entrega Nº 18, hay una excelente introducción al tema de las Clases. Les recomiendo encarecidamente su lectura y puesta en práctica práctica (fin de la nota).
Si usas VBA para hacer tus programas de Microsoft Access más inteligentes y especialmente si usas formularios Desvinculados, casi con seguridad te darás cuenta de que la conveniencia de los módulos de clase bien vale la pena el esfuerzo inicial. Los siguientes tips son una sencilla sencilla introducción al uso de módulos de clase y constituyen una iniciación a tu propia propia programación orientada a objetos. objetos. El tutorial asume que estás razonablemente familiarizado con el uso de VBA en aplicaciones de Access. Parte 1: Un sencillo ejemplo
Introducción
1
En este primer ejemplo, vamos a crear un módulo de clase muy básico al cual llamaremos clsSimple. Le agregaremos algunas propiedades que que podremos establecer establecer y cambiar usando código VBA normal. También mostraremos como usar el comando Stop en las pruebas de código para seguir “vivos” en la memoria.
Instrucciones:
1. 2. 3. 4.
Abrir el editor de VBA (Ctrl + F11) En el explorador de proyectos hacer: clic derecho -> insertar -> módulo de clase. En la venta de propiedades en la propiedad (Name) escribir: clsSimple. Guardar el módulo (Ctrl + S) haciendo clic en aceptar con el nombre propuesto (clsSimple) 5. Escribir en el módulo el siguiente código
6. Ahora, creemos un poco de código de prueba; en el explorador de proyectos, insertemos un módulo estándar que guardaremos con el nombre de pruebaSimple 7. Escribir en el módulo pruebaSimple el siguiente código:
8. Abrir la ventana inmediato (Ctrl + G)
2
9. Escribir fncpruebaSimple y pulsar la tecla Enter Esto hará que se muestren los valores de las propiedades que hemos establecido en nuestro programa. El sistema debería resaltar la palabra “Stop” en amarillo. La ventana inmediato debería mostrar resultados como el siguiente:
De acuerdo, no es nada asombroso, pero es un comienzo. Hagamos algunas observaciones de lo visto hasta ahora:
Notemos cómo Access nos ofrece una lista de la cual elegir después que hemos escrito la palabra oSim seguida del punto Incluso cuando declaramos el tipo de dato con: Dim oSim as… , Access ya sabía de la existencia de nuestra clase.
Si usamos el menú Ver -> Examinador de objetos o simplemente pulsamos F2, podremos buscar clsSimple y ver los miembros de ésta clase listados igual que todas las clases que ya vienen con Access
De vuelta a las instrucciones…
10. El comando Stop en nuestro procedimiento ha detenido el programa dejando que nuestro objeto continúe “vivo” en memoria. Podemos us ar la ventana inmediato para hacer cambios en las propiedades del objeto. Por ejemplo, escribamos estos comandos en la ventana inmediato:
Al pulsar la tecla Enter nos debería mostrar el número 99, que es nuevo valor de la propiedad oSim.Valor, la cual acabamos de cambiar. 11. Para finalizar el programa, presionemos F5 ó: Ejecutar -> Continuar.
3
¿Qué hemos aprendido?
Este muy sencillo ejemplo nos ha mostrado cómo crear el objeto personalizado clsSimple con las propiedades Idpedido, NombreCliente, y Valor; establecimos valores para dichas propiedades y luego hicimos algunas cosas con ellas- aunque sólo fuera mostrarlas en pantalla. La creación de una propiedad es algo tan sencillo como crear una variable pública en el módulo de clase También vimos como configurar nuestro código de prueba de manera de dejar nuestro objeto “vivo” en la ventana inmediato y poder hacer pruebas y otras “travesuras” con él. Más
Como práctica adicional, abramos la ventana inmediato de nuevo (Ctrl + G) y escribamos los siguientes comandos:
Acabamos de crear el objeto os “en el aire”, por así decirlo. El comando que realizó ésta acción fue: set os = new clsSimple. Al presionar la tecla Enter después de cada instrucción, observamos cómo se muestran (en los sitios donde se observa el subrayado en la imagen) los valores contenidos en las propiedades del objeto, así podemos ver en “tiempo real” cuáles son los valores por defecto de dichas propiedades y cuales valores toman según las manipulemos. Debido a que el objeto no está declarado dentro de un módulo real, no disponemos de la lista de autocompletado ésta vez, sin embargo, aún podemos asignar y recuperar sus propiedades Preguntas para investigar
1. ¿Cuáles son los valores por defecto de las propiedades de nuestros nuevos objetos cuando se crean por primera vez? 2. ¿Qué pasa si olvidas un nombre y escribes, digamos, os.Val en vez de os.Valor? 3. ¿Toma en cuenta Access la diferencia entre mayúsculas y minúsculas si escribes os.valor, os.VALOR u OS.valor?
4
Parte 2. Propiedades Sólo Lectura Introducción
En nuestro primer ejemplo clsSimple, todas las propiedades –IdPedido, etc. – podrían ser alteradas por un programa VBA porque fueron declaradas como Public. Si queremos que algunas de nuestras propiedades sean de sólo lectura, necesitamos hacer o declarar las variables como Private y usar la instrucción Property get Instrucciones
1. Creemos una nueva clase llamada clsReadOnly 2. Escribamos el siguiente código:
3. En la ventana inmediato, intentemos ingresar los siguientes comandos:
Esta vez aún podemos obtener el valor de la propiedad del objeto, pero no podemos establecer ése valor usando una instrucción tal como oro.IdPedido = 99. En realidad, éste ejemplo en particular no sirve de mucho, pero en posteriores lecciones veremos cómo éste código puede ser usado de manera muy efectiva para proteger propiedades importantes tales como IdPedido de cambios accidentales. Lo opuesto a la instrucción Property get es la instrucción Property let . Si consultamos la ayuda respecto a éste tema, podríamos encontrar ejemplos como éste:
5
De hecho, no hay diferencia entre esto y declarar una variable como Public, tal como lo hicimos en nuestro primer ejemplo. De éste modo, sólo tomaría más código. Sin embargo. Hay cosas muy útiles que hacer con la instrucción Property Let, tal como limitar los valores que la propiedad pueda tomar. Una nota acerca de la convención de nombres
El prefijo cls usado para nombrar los módulos de clase en la ventana de módulos es otra convención. Podemos dar a nuestras clases el nombre que queramos, pero realmente ayuda si somos organizados desde el principio. Al tener todos los nombres de nuestros módulos de clase empezando por cls los diferenciaremos de los módulos estándar Las instancias de objetos definidos en código VBA empiezan con “o ” minúscula tal
como oSim. Repetimos, hay numerosas convenciones para esto. Es cuestión de gustos personales
Parte 3. Haciendo que nuestra clase haga algo… Introducción
Hasta ahora hemos visto cómo crear un objeto con propiedades; ahora vamos a hacer que el objeto haga algo. Nuevamente, usaremos un ejemplo sencillo para mostrar los elementos básicos. Instrucciones
1. Hagamos una copia de nuestro primer módulo de clase: en el explorador de proyectos hacer clic derecho en clsSimple -> Copiar -> Pegar. Llamaremos al nuevo módulo clsSimpleMetodo 2. Hagamos doble clic en clsSimpleMetodo y editemos el código como se ve a continuación:
6
3. Guardemos los cambios y editemos el módulo pruebaSimple e insertemos un nuevo procedimiento con el nombre de PruebaImpuesto. 4. Editemos el código:
5. Guardemos los cambios y en la ventana inmediato escribamos el nombre del procedimiento: pruebaImpuesto.
Qué hemos aprendido:
7
La adición de código en la función pública Impuesto de nuestro objeto, ha creado un método que calcula exactamente el 10 por ciento de cualquiera que sea el valor de la propiedad Valor en un momento dado. De nuevo, difícilmente podría servir éste ejemplo para probar las capacidades de nuestra computadora, pero se podría complicar todo lo que queramos. Que significa esto:
Incluso con éste sencillo ejemplo el programador usuario del objeto clsSimpleMetodo no necesita saber los detalles de cómo el Impuesto se calcula. Él sólo usa la expresión o. Sim en su código. Además, desde el punto de vista de un nivel más alto de mantenimiento de programas, si queremos cambiar la tasa de impuesto a, dig amos, 12 %, sólo tenemos que alterar un número en el código en clsSimpleMetodo, y luego quienquiera que haya usado la expresión oSim.Impuesto donde sea en el programa, obtendrá la respuesta correcta automáticamente. Probablemente estemos pensando que, hasta ahora, todo esto no difiere mucho del uso de funciones públicas en un módulo estándar de código, aparte de la lista de autocompletado. En posteriores ejemplos veremos porqué el uso de clases es mucho más poderoso. Un caso más complicado
Si las leyes impositivas se vuelven más complicadas de manera que, por ejemplo, el impuesto será de 10% si el valor es de 100 o menos y de 12 % en los demás casos, podemos cambiar el código de nuestro módulo clsSimpleMetodo de la manera siguiente:
Lo cual debería producir el resultado siguiente en la ventana inmediato:
8
Pregunta:
¿Qué crees que significa la palabra Me en la expresión Me.Valor ? Parte 4. Conectando don la base de datos
¿Cómo conectamos los módulos de clases con las tablas de nuestra base de datos? Armemos un ejemplo elemental donde leamos los datos de clientes de una tabla usando un objeto cliente. Instrucciones
1. Creemos una nueva tabla llamada tblClientes con los siguientes campos: Nombre del campo Tipo de datos Ajustes IdCliente Auto numérico Clave Primaria NombreCliente Texto Direccion Texto Telefono Texto TasaDescuento Número Doble, formato porcentaje Terminos Número Entero TasaDescuento es el descuento estándar que podríamos dar a cada cliente en
particular y Terminos es el número de días de crédito que le damos. 2. Ingresemos algunos datos “inventados” para crear un par de registro s. Asegurémonos de no dejar ningún campo vacío por el momento: Tabla tblClientes: Datos de ejemplo
IdCliente 1
NombreCliente Pedro
Direccion Calle 123
2
Susana
Calle cualquiera
9
Telefono (02) 1234 1234 (02) 2345 5666
TasaDescuento 2.5
Terminos 30
5
60
3. Creemos un nuevo módulo de clase llamado clsCliente y escribamos en él el siguiente código:
10
4. En la ventana inmediato, escribamos los siguientes comandos (hemos colocado comillas simples delante de las respuestas esperadas):
¿Qué se ha logrado con esto?
Estos comandos nos han permitido realizar varias tareas:
Creamos un nuevo objeto oCli de la clase clsClientes en memoria con el comando set oCli = new clsCliente Cargamos, uno por uno, los datos de los dos primeros registros de la tabla tblClientes de la base de datos en el objeto (y pudo habernos dicho si fue o no exitoso el procedimiento). Para ello utilizamos el comando : ? oCli.Cargar()
11
Mostramos en pantalla los valores del objeto, usando comando como éste: oCli.NombreCliente.
Qué significado tiene todo lo anterior:
Un simple comando o.Cli.Cargar(n) “irá” y cargará todos los campos de un registro especifico en la tabla tblClientes usando el ID del cliente en memoria. Esto se puede hacer tanto en la ventana inmediato como a lo largo de nuestro código ordinario. Todo el código de manipulación de la base de datos está en el módulo de clase Nos podemos referir a cada propiedad de nuestro objeto con la sintaxis oCli.propiedad. Podemos usar esas propiedades en nuestro código normal igual que cualquier otra variable. Es cierto que tenemos que escribir más código al principio cuando creamos el módulo de clase pero esto quedo más que retribuido en la simplicidad del código de nuestra aplicación principal.
En la próxima parte veremos cómo guardar los datos de nuestro objeto en la base de datos. Algunas observaciones:
El uso de una constante privada en el módulo de clase para referirnos al nombre de la tabla de la base de datos: Private Const scTabla as string = tblClientes, facilita el cambio de nombre de la tabla o la realización de una copia del módulo para ser usada en otro objeto. También previene equivocaciones al referirnos a la tabla en cualquier lugar de nuestro código. El uso de la opción dbOpenForwardOnly agiliza el acceso a los datos de la tabla.: Set rs = CurrentDb.Openrecordset (sQry,dbOpenForwardOnly)
Hemos definido la función Cargar as Boolean para devolver True si fue exitosa o False si falló
Public Function Cargar (Id as Long) as Boolean Cargar = False ‘Haz el trabajo…ve a salida si fallas o en caso de error Cargar = True Salida: Exit Function
Hemos declarado la propiedad IdCliente para prevenir cambios accidentales.
12
Mi criterio personal para nombrar los Campos Autonuméricos es usar la palabra completa IdCliente o IdFactura, por ejemplo, en vez de usar sólo ID. Esto simplifica mucho la creación de consultas cuando tienes que unir tablas. Si deseo copiar el código de un modulo de clase para crear una nueva, sólo tengo que hacer una edición global para cambiar la palabra “Cliente” a, digamos, “Factura”. Parte 4. Guardando en la base de datos
Introducción:
Esta lección explica cómo usar los módulos de clase para capturar datos de un formulario “estático” o desvinculado y guardarlos en una tabla de la base de datos.
El ejemplo muestra cómo manipu lar un sencillo objeto “Pedido” mediante la creación de un nuevo módulo de clase llamado clsPedido, una tabla “tblPedidos” en la base de datos un un formulario “frmCrearPedido” el cual usará el objeto para guardar un nuevo registro en la base de datos. Instrucciones:
1. Creemos una nueva tabla llamada tblPedidos con los siguiente campos:
2. Creemos una relación “uno” a “ muchos” entre el campo IdCliente de la tabla tblClientes y el campo IdCliente de la tabla tblPedidos. Exijamos integridad
referencial.
13
3. Creemos un modulo de clase llamado clsPedido e ingresemos el siguiente código:
14
4. Creemos un formulario llamado frmCrearPedido, el cual no estará basado en ninguna tabla. Agreguemos los siguientes controles:
15
Nombre del control
cboCliente
Tipo
Cuadro Combinado
Propiedades
Origen en la tabla tblClientes.IdCliente
txtItem
Cuadro de texto
Txtcantidad
Cuadro de texto
txtPrecioUnitario
Cuadro de texto
Txtvalor
Cuadro de texto
Visible: No; origen de datos: = [txtCantidad]*[txtPrecioU nitario]
btnCerrar
Botón de comando
(Ver abajo)
btnOk
Botón de comando
(Ver abajo)
5. Añada el siguiente código al formulario:
16
17
6. Abramos el formulario e ingresemos algunos datos de ejemplo:
18
7. Hagamos clic en el botón OK. Un nuevo registro debería crearse en la tabla de la base de datos. Qué hemos hecho:
Nuevamente, esto parece mucho esfuerzo para lograr tan poco. Hemos dejado que el usuario llene algunos campos en un formulario y luego hemos guardado los datos en un registro en la base de datos Sin embargo, este ejemplo pone de relieve los elementos clave de la técnica. Cuando trabajemos con objetos complejos y queramos mantener a los usuarios lejos de la base de datos hasta el último minuto, ahí es cuando estas técnicas entran en acción.
La clave de este ejemplo es el objeto oPedido creado en la sección de declaraciones del módulo del formulario.
El formulario no está vinculado a la tabla tblPedidos y no podrá hacer daño alguno hasta el momento apropiado, no importa qué haga el usuario.
Cuando llega el momento de “hacer el daño”, el código tras el formulario,
recoge los valores que serán asignados a las propiedades del objeto y luego usa el método Crear del objeto para crear una nueva entrada en la tabla.
Observemos cómo hemos hecho uso del punto en expresiones del tipo Me.NombreControl para referirnos a los valores de los controles en el
19
formulario. Sabemos que la documentación nos recomienda usar el signo de exclamación (!), pero esta forma no sólo es una sintaxis perfectamente válida sino que sino que nos arrojara un error inmediato en caso de existir al tratar de compilar nuestro código, cosa que la sintaxis Me!NombreControl no hará. Sería bueno hacer una edición global en todos
los módulos de formularios para remplazar” Me!” con “Me.”.
El “daño" real es hecho por un simple comando: oPedido.Crear. Lo que sea
que haga dicho comando no es de la incumbencia del programador “usuario” de la clase al crear el formulario, siempre y cuando el haya
configurado todas las propiedades correctamente
Fijémonos cómo el código hace uso del valor de retorno del método Crear para ver si la tarea se llevó a cabo con éxito o no:
Y no sólo eso. El objeto ya tiene su nuevo Id almacenado en la propiedad oPedido.IdPedido.
Si queremos ser más “Sofisticados”, podemos envolver el método en una transacción:
Parte 5 (y final). Editando y borrando objetos
Introducción
El Siguiente ejemplo nos enseña cómo extender nuestra clase clsPedido con métodos que nos permitan editar y borrar registros en la base de datos.
20
Instrucciones:
1. Creemos un nuevo módulo de clase llamado clsPedido1 con el siguiente código:
21
22
23
2. Experimentemos con este nuevo objeto en la ventana inmediato como se ve a continuación:
24
Si queremos experimentar todo esto más bien en un fragmento de código, no debemos olvidar la sustitución de “?” por “Debug.Print”. (Pero si hemos llegado hasta aquí ya deberíamos saberlo). Observaciones acerca del código:
Esta vez hemos hecho uso de la función Nz al leer los los datos de la base de datos con el método Cargar. Me.Item = Nz(.field s(“Item”) ,0)
Esto maneja el problema (con el que quizá ya nos hemos topado), de pretender asignar un valor nulo de nuestra base de datos a alguna propiedad de nuestro objeto
25
El método Actualizar que utiliza una consulta para filtrar los registros, también dispone de un mecanismo de verificación mediante el uso d e la propiedad RecordCount del Recordset si un registro en particular no es encontrado.
Si usamos un procedimiento privado en un módulo de clase tal como GuardarRegistro, éste puede ser usado dentro del módulo de clase como cualquier otro procedimiento local, pero no puede ser usado externamente. Intentemos esto :
Al pulsar Enter emerge un error como éste:
La declaración del módulo como Private significa exactamente eso: lo que sea que haga el procedimiento, pertenece al ámbito privado del módulo y no puede ser usado de manera accidental por un “intruso”.
El método borrar simplemente usa una consulta SQL de eliminación. Observemos el uso del parámetro dbFailOnError con el cual nos aseguramos de que cualquier error sea capturado.
26
Aun cuando éste código podría lucir un poco complicado, una vez se ha escrito por primera vez, podría ser fácilmente copiado en otros objetos y ser cambiado con una sencilla edición global. FIN
27