You are on page 1of 32

CURSO DE VB

CAPTULO 181

ndice de contenido
TIPOS, COLECCIONES Y CLASES..................................................................................................2
INTRODUCCIN...........................................................................................................................2
TIPOS..............................................................................................................................................2
COLECCIONES..............................................................................................................................6
DEFINIR UNA COLECCIN....................................................................................................6
AADIR ELEMENTOS A UNA COLECCIN........................................................................7
CONTAR ELEMENTOS DE UNA COLECCIN....................................................................7
ELIMINAR ELEMENTOS DE UNA COLECCIN.................................................................7
RECORRER LOS ELEMENTOS DE UNA COLECCIN.......................................................8
UN EJEMPLO CON TODO LO ANTERIOR............................................................................8
CLASES...........................................................................................................................................9
TRABAJANDO CON LAS CLASES...........................................................................................11
EXPORTANDO EL MDULO DE CLASE............................................................................12
SEGUIMOS CON EL TRABAJO CON CLASES...................................................................13
UTILIZANDO LAS PROPIEDADES: PROCEDIMIENTO PROPERTY..............................16
PROPERTY LET..................................................................................................................16
PROPERTY GET.................................................................................................................16
PROPERTY SET..................................................................................................................17
APLIQUEMOS EL PROCEDIMIENTO PROPERTY........................................................17
UNAS BREVES EXPLICACIONES TERICAS BASADAS EN TODO LO ANTERIOR. 21
UN EJEMPLO INTEGRNDOLO CON ACCESS.....................................................................23
PARA FINALIZAR ESTE CAPTULO........................................................................................31

1 La BD donde estn los ejemplos de este captulo os la podis bajar aqu.

1
Vistame en http://siliconproject.com.ar/neckkito/
TIPOS, COLECCIONES Y CLASES

INTRODUCCIN
El objetivo de este captulo es llegar a comprender las
clases. Sin embargo, para ello es necesario asimilar dos
conceptos clave: los tipos y las colecciones. Si bien no son
lo mismo (lgicamente) las ideas que subyacen en cada uno
de ellos nos allanarn el camino para llegar a las clases.

Es por esto por lo que empezaremos desarrollando los que son los tipos, cmo se definen, etc.,
y haremos lo mismo con las colecciones (que, adems, ya nos debera sonar de algo si
hemos seguido todo este curso hasta aqu).

Como utilizaremos los conceptos explicados cuando hablbamos de matrices, si notis que
tenis un momento de debilidad memorstica, quiz sera interesante que tuvierais a mano el
captulo 9, donde se habla de ellas.

Os advierto que este captulo quiz pueda resultaros algo complejo, sobre todo en la parte final
del mismo y en especial en el apartado Un ejemplo integrndolo con Access, bsicamente
porque se mezclan no slo cosas de este captulo sino elementos que hemos ido explicando (y
aprendiendo, supongo ) durante este curso. Pensad que la finalidad es podernos construir
nuestro propio mdulo de clase (todo un lujazo para nuestra aplicacin).

Empecemos pues.

TIPOS
Nuestro buen amigo Access nos dice, refirindose a la instruccin Type, lo siguiente: <<Se usa
en el nivel de mdulo para definir un tipo de datos definido por el usuario que contiene uno o
ms elementos>>.

Vayamos por partes:

Se usa a nivel de mdulo. Pues vaya, ya tenemos una primera pista.


Tipo de datos. Sabemos que hay datos numricos, booleanos, de texto... Qu tipo de
datos ser?
Definido por el usuario. Ergo no es un tipo de datos llammosle estndar, sino que
es el usuario el que se lo saca de la manga.
Contiene uno o ms elementos. Eso me suena a matrices, verdad?

Sigamos. La estructura para definir un tipo es la siguiente:

PUBLIC/PRIVATE TYPE nombreTipo


nombreElemento1 AS tipoDato

nombreElementoN AS tipoDato
END TYPE

OK. Ya tenemos la estructura para definir un tipo. Y los elementos?

2
Vistame en http://siliconproject.com.ar/neckkito/
Pues los elementos deben ser definidos dentro de un procedimiento.

Lo anterior nos lleva a tener que remarcar dos puntos:

La declaracin del tipo NO va dentro de un procedimiento,


sino que debemos situarlo en la cabecera del mdulo.
La declaracin de los elementos S va dentro de un
procedimiento.

Vamos a realizar un pequeo ejercicio muy simple para


empezar a entender lo anterior. Despus complicaremos un
poco el asunto.

En una BD en blanco vamos a insertar un mdulo estndar, que llamaremos mdlDefinoTipos.


Vamos a crearnos un tipo personalizado, que llamaremos CodigoColor. La idea es que nuestra
empresa tiene, como mecanismo de seguridad, un cdigo de colores: a cada color le
corresponde un grado de peligrosidad.

Como hemos comentado antes, la definicin de los tipos debe ir en la cabecera del mdulo
(debajo de Option Compare Database / Option Explicit). As, los elementos que componen
nuestro tipo sern dos:

1.- Nombre del color


2.- Significado de peligro

Deberamos pues definirlo as:

Public Type CodigoColor


nombre As String * 10
significado As String * 25
End Type

Como veis, las variables que indican la definicin de los elementos son, en este caso, de tipo
texto String. Adems, hemos indicado su longitud mxima (a travs de * 10 y * 25).

Segunda fase: rellenar los elementos.

Como es el primer ejemplo fcil slo vamos a rellenar los datos de un color. Como comentaba
antes, una vez entendido lo que hace nuestro cdigo pondremos un ejemplo ms complejo.

Para rellenar los elementos del tipo vamos a utilizar un procedimiento pblico, que llamaremos
rellenaCodigos. Lo escribiramos as, inmediatamente debajo de nuestra definicin de tipo
personalizado CodigoColor:

Public Sub rellenaCodigos()


'Declaramos una variable, dicindole que es de nuestro tipo personalizado
Dim vColor As CodigoColor
'Rellenamos los valores
vColor.nombre = "Verde"
vColor.significado = "Sin peligro"
'Mostramos los resultados

3
Vistame en http://siliconproject.com.ar/neckkito/
MsgBox vColor.nombre & vColor.significado, vbInformation, "DATOS"
End Sub

Fijaos en que:

Debo declarar la variable como mi tipo personalizado


Debo indicar a qu elemento me refiero, y rellenarlo,
utilizando la estructura: <variable.elemento = valor>

Si nos situamos en nuestro procedimiento y pulsamos F5


veremos qu nos muestra el MsgBox.

Compliquemos un poco ms la cosa. Supongamos que tenemos un listado de pases con sus
monedas. El listado que utilizaremos ser el siguiente:

1- USA - Dlar
2- Espaa - Euro
3- Japn - Yen

Nos crearemos, en nuestro mdulo, un nuevo tipo, al que llamaremos Monedas, de la manera
siguiente:

Public Type tipoMoneda


nombre As String * 10
Moneda As String * 10
End Type

Y nos crearemos un procedimiento llamado usaMoneda, as:

Public Sub usaMoneda(ByVal indice As Integer)


'Declaramos una variable como nuestro tipo, pero en forma de matriz
Dim paisMoneda(1 To 3) As tipoMoneda
'Rellenamos los datos
paisMoneda(1).nombre = "USA"
paisMoneda(2).nombre = "Espaa"
paisMoneda(3).nombre = "Japn"
paisMoneda(1).moneda = "Dlar"
paisMoneda(2).moneda = "Euro"
paisMoneda(3).moneda = "Yen"
'Devolvemos un MsgBox con la informacin
MsgBox "El pas " & paisMoneda(indice).nombre & " usa la moneda " &
paisMoneda(indice).moneda, _
vbInformation, "RESULTADO"
End Sub

Finalmente, nos creamos un formulario en blanco y, en un botn de comando, escribimos el


siguiente cdigo2:

Private Sub cmdProcedimientousaMoneda_Click()

2 El tema de control de errores os lo dejo para vosotros

4
Vistame en http://siliconproject.com.ar/neckkito/
'Declaramos las variables
Dim vCod As Variant
'Solicitamos al usuario un cdigo de pas
vCod = InputBox("Introduzca cdigo del pas (nmero
del 1 al 3)", "CDIGO PAS", "1")
'Llamamos al procedimiento usaMoneda()
Call usaMoneda(vCod)
End Sub

Pensad que la gracia del ejemplo est en entender la


mecnica de cmo funciona la definicin de tipos
personalizados.

Tambin pensad que podemos reutilizar nuestra definicin de tipo para otras acciones (si lo
planificamos bien nos puede salir una definicin de tipos bastante universal).

Por ejemplo, si creamos otro procedimiento para saber en qu moneda debemos pagar a un
cliente, sabiendo su cdigo de cliente, slo deberamos escribir un procedimiento especfico
para ello, sin tener que volver a definir otro tipo.

Es decir, en nuestro mdulo podemos escribir lo siguiente:

Public Sub clienteMoneda(ByVal Indice As Integer)


Dim cliMon(1 To 3) As tipoMoneda
cliMon(1).nombre = "Meals Co"
cliMon(2).nombre = "Verduras SA"
cliMon(3).nombre = "Arigato"
cliMon(1).moneda = "Dlar"
cliMon(2).moneda = "Euro"
cliMon(3).moneda = "Yen"
MsgBox "Para " & cliMon(Indice).nombre & " debemos pagar usando el " &
cliMon(Indice).moneda, _
vbInformation, "MONEDA DE PAGO"
End Sub

Y el cdigo de nuestro botn sera:

Private Sub cmdProcedimientoclienteMoneda_Click()


'Declaramos las variables
Dim vCod As Variant
'Solicitamos al usuario un cdigo de cliente
vCod = InputBox("Introduzca cdigo del cliente (nmero del 1 al 3)", "CDIGO CLIENTE",
"1")
'Llamamos al procedimiento clienteMoneda()
Call clienteMoneda(vCod)
End Sub

Para finalizar, tened en cuenta que hemos utilizado matrices estticas para definir los ndices
de los datos. No habra ningn problema en utilizar matrices dinmicas si no conocemos, de
antemano, el nmero de elementos que va a haber en la matriz.

5
Vistame en http://siliconproject.com.ar/neckkito/
COLECCIONES
Durante todo el curso hemos estado viendo, en
determinados captulos, distintas colecciones. A modo de
recordatorio, hemos visto la coleccin Fields() de un
recordset, o la coleccin Properties de los controles. En
definitiva, que si nos paramos a pensar un poco podremos
llegar a afirmar aquella frase de en ocasiones veo
colecciones.

Y qu es una coleccin? Nuestro amigo Access la define


as, aadiendo unos comentarios:

<<Un objeto Collection es un conjunto ordenado de elementos a los que se puede hacer
referencia como una unidad.

Comentarios
El objeto Collection permite hacer referencia de forma sencilla a un grupo de elementos
relacionados como un nico objeto. Los elementos o miembros de una coleccin slo tienen
que estar relacionados por el hecho de existir en la coleccin. Los miembros de una coleccin
no tienen que compartir el mismo tipo de dato>>.

Veamos:

Es un conjunto ordenado de elementos Ya sabemos que puede contener varios


elementos, de manera ordenada.
Se puede hacer referencia a los mismos como una unidad Para entendernos, yo
puedo tener un Porshe, un Mercedes, un Ferrari y un Lexus (por si alguien tena dudas
esto es un ejemplo, y no tengo ninguno de los cuatro ). Pues bien, cuando quiero
referirme a todos ellos no los cito uno a uno, sino que digo mis coches. Luego,
misCoches es mi unidad, mi coleccin.
Los elementos slo tienen que estar relacionados por el hecho de existir en la coleccin
Es decir, si yo digo misCoches, dnde queda mi Harley Davidson? No es un
elemento porque no he creado ninguna relacin con la coleccin misCoches. Ahora bien,
si yo utilizo otra coleccin, y la llamo misMediosDeTransporte, ya hemos establecido
relacin, por lo que ahora s estoy citando misCoches y misMotos a la vez.
Los miembros no tienen que compartir el mismo tipo de dato Fcil: en mi coleccin
misMediosDeTransporte mi Lexus es un dato tipo coche, pero mi Suzuki es un dato
tipo moto, y mi Boeing es un dato tipo avin... y no olvidemos que s estn todos
en mi coleccin.

Con todo lo anterior ya vemos que podemos crearnos nuestras propias colecciones.

DEFINIR UNA COLECCIN


Para crear una coleccin debemos definirla como, precisamente, una coleccin, mediante la
palabra COLLECTION.

En definitiva, que si queremos crearnos la coleccin misCoches deberamos declararla as:

Public misCoches As Collection

y definirla as:

Set misCoches = New Collection

6
Vistame en http://siliconproject.com.ar/neckkito/
Nos debera sonar tambin la idea de que esos dos pasos podemos
resumirlos en uno, declarando la coleccin de la siguiente manera:

Public misCoches As New Collection

AADIR ELEMENTOS A UNA


COLECCIN
Para aadir elementos debemos utilizar la palabra ADD.

La estructura sera:

nomColeccin.Add Elemento

o bien

nomColeccion.Add Elemento, Clave

Por ejemplo, si yo quiero aadir mi coche Porshe Carrera a la coleccin escribira lo siguiente:

misCoches.Add Porshe Carrera

Si, adems, quisiera identificar ese coche con una palabra clave, podra aadirla tambin con el
ADD. Por ejemplo, supongamos que mi clave para el Porshe Carrera es PorCar; luego
escribira:

misCoches.Add Porshe Carrera, PorCar

CONTAR ELEMENTOS DE UNA COLECCIN


Para contar los elementos de una coleccin utilizamos la palabra COUNT.

La estructura sera muy sencilla, como imagino que ya habremos intuido:

nomColeccion.Count

Es decir:

misCoches.Count

ELIMINAR ELEMENTOS DE UNA COLECCIN


Para eliminar elementos utilizamos la palabra REMOVE.

Los elementos de una coleccin tienen todos un ndice, que vendra a ser el identificador de la
posicin que ocupan en la coleccin. Sabiendo esto, y tambin sabiendo que podemos eliminar
un elemento por su palabra clave, la estructura para eliminar sera:

nomColeccion.Remove (ndice)

o bien

7
Vistame en http://siliconproject.com.ar/neckkito/
nomColeccion.Remove (clave)

Es decir, que si mi Porshe Carrera tuviera el ndice 6, podra eliminarlo as:

misCoches.Remove (6)

o as

misCoches.Remove (PorCar)

RECORRER LOS ELEMENTOS DE UNA


COLECCIN
Para recorrer los elementos de una coleccin debemos utilizar el bucle FOR EACH...NEXT. En
este curso hemos visto en algunos ejemplos cmo se utiliza dicho bucle. Su estructura es:

FOR EACH <elemento> IN <coleccion>


'Cdigo
NEXT <elemento>

Como vamos a ver un ejemplo en el siguiente apartado no insisto ms aqu.

UN EJEMPLO CON TODO LO ANTERIOR


Vamos a realizar un pequeo ejercicio con todo lo que acabamos de aprender. Vamos a
crearnos un nuevo mdulo, al que llamaremos mdlColeccionCoches.

Public Sub colecCoches()


'Declaramos las variables
Dim cocheBorrado As String
'Declaramos la coleccin
Dim misCoches As Collection
'Definimos la coleccin
Set misCoches = New Collection
'Declaramos el contenedor de elementos de la coleccin
Dim elCoche As Variant
'Aadimos los elementos de la coleccin
With misCoches
.Add "Porshe Carrera", "PorCar"
.Add "Ford Mustang", "ForMus"
.Add "Mazda RX5", "MazRx5"
.Add "Toyota Celica", "ToyCel"
End With
'Mostramos cuantos coches tenemos
MsgBox "Tengo " & misCoches.Count & " cochazos", vbExclamation, "#COCHES"
'Recorremos la coleccin
For Each elCoche In misCoches
MsgBox "Un coche es un " & elCoche, vbInformation, "MIS COCHES"
Next elCoche
'Cogemos el valor del coche que vamos a borrar
cocheBorrado = misCoches("PorCar")
'----------------------------------------------
'Esta expresin sera equivalente a la anterior
'cocheBorrado = misCoches.Item(1)

8
Vistame en http://siliconproject.com.ar/neckkito/
'----------------------------------------------
'Borramos el primer coche
misCoches.Remove (1)
MsgBox "Oh! No recordaba que el primer coche lo vend
por un pastn" _
& vbCrLf & vbCrLf & "Ahora slo tengo " &
misCoches.Count & " 'cochecitos'", _
vbExclamation, "#COCHES"
MsgBox "Quiero decir, que el coche que vend fue el " &
cocheBorrado, vbInformation, "VENDIDO"
End Sub

Y slo nos queda, en cualquier formulario, aadirle este cdigo a un botn de comando:

Private Sub cmdLlamaColecCoches_Click()


Call colecCoches
End Sub

Si analizis el primer cdigo veris cmo he manipulado la coleccin y sus propiedades segn
lo que os he estado explicando en apartados anteriores. No creo que tenga mayor dificultad
para nuestros ya entrenados cerebros

Slo quisiera llamaros la atencin sobre algo que no habamos comentado an, y que es la
propiedad ITEM. Fijaos que cuando asigno valor a la variable <cocheBorrado> lo hago a travs
de su clave, as:

cocheBorrado = misCoches("PorCar")

Pero si no tuviera clave, o mi gua fuese el ndice del elemento en la coleccin, podra utilizar
esta otra expresin:

cocheBorrado = misCoches.Item(1)

para hacer referencia al elemento (item) nmero 1 de la coleccin.

CLASES
Nuestro amigo Access nos define una clase como <<Definicin formal de un objeto. La clase
acta como plantilla desde la que se crea una instancia de un objeto en tiempo de ejecucin.
La clase define las propiedades del objeto y los mtodos utilizados para controlar su
comportamiento>>.

Veamos:

Define un objeto. Eso significara que lo que nos permite crear son objetos, y en los
captulos anteriores hemos visto algunas de las muchas cosas que se pueden hacer con
los objetos.

Acta como plantilla desde la que se crea una instancia de un objeto. Ya sabemos que
lo que nos estamos creando es una plantilla, y que gracias a esa plantilla vamos a crear
una instancia del objeto. Y qu significa esto? Que nosotros no vamos a trabajar con la
plantilla directamente cuando creemos un objeto, sino que vamos a trabajar con una
instancia.

9
Vistame en http://siliconproject.com.ar/neckkito/
Quiz lo anterior pueda resultar un poco confuso, pero un
ejemplo grfico creo que nos ayudar: supongamos que yo
creo una clase que se llama rectngulo. Cuando necesito
un objeto rectngulo llamo a la clase y creo el objeto. En
realidad creo una instancia del objeto: todo el trabajo que
realice se har sobre esa instancia, no sobre la plantilla. Es
decir:

Se crea una instancia del objeto en tiempo de ejecucin. Lo que significa, para
entendernos, que se crea mientras tenemos Access en marcha.

La clase define las propiedades del objeto y los mtodos utilizados para controlar su
comportamiento. Ya sabemos pues que el objeto tendr propiedades y mtodos, y que
podremos establecer sus valores para que la instancia se comporte segn nuestros
deseos.

Aunque no hayamos sido conscientes con los ejemplos que hemos ido aprendiendo durante
este curso estbamos realizando este proceso. Por poner un ejemplo fresco, recordamos el
captulo dedicado al Scripting Runtime, en concreto el ejemplo de nuestro diccionario
(captulo 17)?

Pues bien, cuando escribamos:


'Declaramos las variables
Dim abv As Object
'Creamos el objeto abv
Set abv = CreateObject("Scripting.Dictionary")
'Aadimos los significados de las abreviaturas
abv.Add "DDCG", "Dar de comer al gato"

fncMiTip = abv.Item(vAbreviado)

Mediante la lnea del <Set abv...> estbamos creando la

10
Vistame en http://siliconproject.com.ar/neckkito/
instancia del objeto de la clase Scripting.Dictionary. La
estbamos creando, evidentemente, en tiempo de ejecucin
(no parbamos Access para poder crear dicho objeto) y, a
continuacin, manipulbamos, en este caso, un mtodo de
la clase, que era ADD, y una propiedad, en este caso, ITEM.

Espero que con lo anterior tengamos meridianamente claro


qu es una clase y los elementos que la componen, porque
es bsico para poder comprender lo que veremos en los
apartados siguientes

TRABAJANDO CON LAS CLASES


Vamos a ver cmo podemos trabajar con una clase personalizada a travs de un ejemplo.
Vamos a planificar primero las bases de nuestro proceso:

La clase se llamar clsVehic, y nos recoger los vehculos de que disponemos.


Tendremos tres tipos de vehculos: coches, motos y camiones.
Cada vehculo tendr unas caractersticas determinadas, que recogeremos a travs de
variables pblicas.
Con la informacin introducida, ms informacin que introduciremos a futuro, en tiempo de
ejecucin, nuestro mdulo de clase realizar una serie de operaciones.

Voy a explicar el proceso relacionndolo con los puntos anteriores, para que podis seguir
mejor el hilo de la explicacin.

Para cumplir el punto nos vamos al editor de VB y en el men Insertar aadimos un mdulo
de clase. Lo guardamos como clsVehic.

Para cumplir los puntos y vamos a definir las caractersticas que necesitaremos. Para ello
escribimos en nuestro mdulo de clase lo siguiente:

Option Compare Database


Option Explicit

Public claseVehic As String 'Si es coche, moto o camin


Public nombre As String 'Nombre del vehculo (v.gr., Porshe)
Public tipo As String 'Tipo del vehculo (v.gr., Carrera)
Public cilindrada As Long 'Cilindrada
Public capacDep As Double 'Capacidad del depsito, en litros

Para cumplir con el punto vamos a necesitar unas funciones que nos calcularan los
resultados. La primera funcin nos unir el nombre con su tipo; la segunda funcin nos
calcular cunto costara llenar el depsito en el momento actual (es decir, que el proceso nos
pedir el importe del litro de combustible en el momento en que necesitemos ese dato).

As, a continuacin de lo anterior escribimos estas dos funciones:

Public Function nomVehic() As String


nomVehic = nombre & " " & tipo
End Function

Public Function costeDeposito(ByVal precioLitro As Double) As Currency


costeDeposito = capacDep * precioLitro

11
Vistame en http://siliconproject.com.ar/neckkito/
If costeDeposito > 150 Then
MsgBox "Qu caro! Mejor dejar el vehculo
aparcado!", vbExclamation, "UFFF"
End If
End Function

La primera funcin nos devuelve una simple concatenacin


de valores, separados por un espacio en blanco. Sin
problemas.

En la segunda funcin se produce una operacin matemtica de multiplicacin. He aadido,


adems, que se lance un MsgBox en funcin del valor obtenido, simplemente para que veis
que se pueden realizar varias operaciones en una misma funcin.

Ya tenemos pues nuestro mdulo de clase creado con todas las caractersticas que
necesitbamos. Ese mdulo de clase lo podramos exportar para poder utilizarlo en diferentes
bases de datos que tuviramos sobre vehculos.

EXPORTANDO EL MDULO DE CLASE


Haremos un inciso y aprovecharemos para explicar cmo exportar el mdulo de clase. Nos
vamos para ello al VBE y seleccionamos el mdulo clsVehic. Hacemos click con el botn
derecho y seleccionamos la opcin Exportar archivo...

Se nos abrir una ventana que nos pedir dnde queremos guardarlo. Como es un mdulo de
clase tendr la extensin cls.

12
Vistame en http://siliconproject.com.ar/neckkito/
Si quisiramos realizar una importacin de clase el proceso sera el mismo (situndonos en
cualquier espacio en blanco en la ventana de proyecto): haramos click derecho y elegiramos
la opcin Importar archivo...

SEGUIMOS CON EL TRABAJO CON CLASES


Prosigamos. Lo explicado hasta ahora de clsVehic estoy seguro que nos recuerda a lo que, al
principio de este captulo, explicbamos sobre Definicin de tipos, verdad? Pues ahora, para
poder continuar, vamos a pasar a utilizar nuestro siguiente elemento: las colecciones,
combinndolo esta vez con el mdulo de clase.

En nuestro formulario de pruebas aadimos un botn de comando, que llamaremos


cmdListaVehiculos, que llamar al procedimiento misVehiculos(), que crearemos en breve. El
cdigo de ese botn sera, simplemente:

Private Sub cmdListaVehiculos_Click()


Call misVehiculos
End Sub

Ahora s nos creamos un mdulo estndar, al que llamaremos mdlVehic. En l vamos a


crearnos una coleccin con nuestros vehculos. As pues, escribiremos el siguiente cdigo 3 (ojo
con el cdigo, que es intenso ):

Public Sub misVehiculos()


'Definimos la coleccin
Set colMisVehic = New Collection
'Declaramos un objeto perteneciente a nuestra clase
Dim unVehiculo As clsVehic
'Declaramos una variable que recoger los elementos de la coleccin, y
'que tambin pertenecer a nuestra clase
Dim elemVehic As clsVehic
'Creamos una instancia del objeto unVehiculo
Set unVehiculo = New clsVehic
'Rellenamos los datos que necesitamos
With unVehiculo
.claseVehic = "Coche"
.nombre = "Porshe"
.tipo = "Carrera"

3 No tengo ni idea de las caractersticas tcnicas de los vehculos que voy a introducir. De hecho es posible que introduzca alguna
salvajada. En definitiva, que me lo voy inventando a medida que escribo. Por ello, no tomis estos valores como referencias
reales.

13
Vistame en http://siliconproject.com.ar/neckkito/
.cilindrada = 3000
.capacDep = 80.5
End With
'Lo aadimos a nuestra coleccin
colMisVehic.Add unVehiculo, "PorCar"
'Rellenamos el siguiente vehculo
Set unVehiculo = New clsVehic
With unVehiculo
.claseVehic = "Coche"
.nombre = "Mercedes"
.tipo = "CLK"
.cilindrada = 2800
.capacDep = 85.7
End With
colMisVehic.Add unVehiculo, "MerCLK"
'Rellenamos el siguiente vehculo
Set unVehiculo = New clsVehic
With unVehiculo
.claseVehic = "Moto"
.nombre = "Suzuki"
.tipo = "Bandid"
.cilindrada = 650
.capacDep = 30.3
End With
colMisVehic.Add unVehiculo, "SuzBan"
'Rellenamos el siguiente vehculo
Set unVehiculo = New clsVehic
With unVehiculo
.claseVehic = "Moto"
.nombre = "Ducati"
.tipo = "Storm"
.cilindrada = 1200
.capacDep = 46.2
End With
colMisVehic.Add unVehiculo, "DucSto"
'Rellenamos el siguiente vehculo
Set unVehiculo = New clsVehic
With unVehiculo
.claseVehic = "Camin"
.nombre = "Mercedes"
.tipo = "Pegaso"
.cilindrada = 4000
.capacDep = 120.7
End With
colMisVehic.Add unVehiculo, "MerPeg"
'Ya podemos mostrar la informacin de la coleccin a peticin del usuario
'No comento esta parte de cdigo porque deberamos entenderla ya perfectamente
Dim vClaseVehic As Variant
Dim vPrecioCombustible As Variant
Peticion:
vClaseVehic = InputBox("Seleccione qu informacin desea: 1-Coches; 2-Motos;" _
& " 3-Camiones; 0-Todos", "INFORMACIN VEHCULOS", 0)
If StrPtr(vClaseVehic) = 0 Then GoTo BorraColeccion
If Not IsNumeric(vClaseVehic) Then
MsgBox "El valor introducido no es vlido", vbCritical, "INCORRECTO"
GoTo Peticion
End If
If vClaseVehic < 0 Or vClaseVehic > 3 Then
MsgBox "El valor introducido no es vlido", vbCritical, "INCORRECTO"
GoTo Peticion
End If
'Por simplificar suponemos que todos utilizan el mismo tipo de combustible
vPrecioCombustible = InputBox("Introduzca el precio por litro de combustible", "PRECIO")
'Tambin, por simplificar, no introduzco elementos de control para el valor introducido
'Si quisirais utilizarlos os podis guiar por los elementos de control que he utilizado
'en el primer InputBox
If StrPtr(vPrecioCombustible) = 0 Then GoTo BorraColeccion
Select Case vClaseVehic
Case 0
For Each elemVehic In colMisVehic
MsgBox "El vehculo tiene las siguientes caractersticas:" & vbCrLf & vbCrLf _

14
Vistame en http://siliconproject.com.ar/neckkito/
& "Clase: " & elemVehic.claseVehic & vbCrLf _
& "Nombre: " & elemVehic.nomVehic & vbCrLf _
& "Cilindrada: " & elemVehic.cilindrada & vbCrLf _
& "Capacidad del depsito: " & elemVehic.capacDep & vbCrLf _
& "Precio de llenado del depsito: " & elemVehic.costeDeposito(vPrecioCombustible), _
vbInformation, "DATOS"
Next elemVehic
Case 1
For Each elemVehic In colMisVehic
If elemVehic.claseVehic = "Coche" Then
MsgBox "El vehculo tiene las siguientes caractersticas:" & vbCrLf & vbCrLf _
& "Clase: " & elemVehic.claseVehic & vbCrLf _
& "Nombre: " & elemVehic.nomVehic & vbCrLf _
& "Cilindrada: " & elemVehic.cilindrada & vbCrLf _
& "Capacidad del depsito: " & elemVehic.capacDep & vbCrLf _
& "Precio de llenado del depsito: " & elemVehic.costeDeposito(vPrecioCombustible), _
vbInformation, "DATOS"
End If
Next elemVehic
Case 2
For Each elemVehic In colMisVehic
If elemVehic.claseVehic = "Moto" Then
MsgBox "El vehculo tiene las siguientes caractersticas:" & vbCrLf & vbCrLf _
& "Clase: " & elemVehic.claseVehic & vbCrLf _
& "Nombre: " & elemVehic.nomVehic & vbCrLf _
& "Cilindrada: " & elemVehic.cilindrada & vbCrLf _
& "Capacidad del depsito: " & elemVehic.capacDep & vbCrLf _
& "Precio de llenado del depsito: " & elemVehic.costeDeposito(vPrecioCombustible), _
vbInformation, "DATOS"
End If
Next elemVehic
Case 3
For Each elemVehic In colMisVehic
If elemVehic.claseVehic = "Camin" Then
MsgBox "El vehculo tiene las siguientes caractersticas:" & vbCrLf & vbCrLf _
& "Clase: " & elemVehic.claseVehic & vbCrLf _
& "Nombre: " & elemVehic.nomVehic & vbCrLf _
& "Cilindrada: " & elemVehic.cilindrada & vbCrLf _
& "Capacidad del depsito: " & elemVehic.capacDep & vbCrLf _
& "Precio de llenado del depsito: " & elemVehic.costeDeposito(vPrecioCombustible), _
vbInformation, "DATOS"
End If
Next elemVehic
End Select
'Borramos los elementos de la coleccin
BorraColeccion:
Dim i As Long
For i = colMisVehic.Count To 1 Step -1 'Realizamos una cuenta atrs
colMisVehic.Remove (i)
Next i
End Sub

Si vemos desde arriba el cdigo veremos claramente (eso espero!) su estructura:

1.- Definimos las colecciones y los objetos, y los relacionamos, mediante dicha definicin, con
el mdulo de clase que hemos creado.
2.- Rellenamos los datos del elementos y lo aadimos a la coleccin.
3.- Repetimos el proceso de rellenado con todos los elementos que queramos.
4.- Solicitamos la informacin al usuario
5.- En funcin de lo que quiere ver el usuario (coche, moto o camin), para lo cual utilizamos
un SELECT CASE...END SELECT, recorremos los elementos de la coleccin a travs de un
bloque FOR EACH...NEXT
6.- En dicho bloque operamos con las propiedades de la clase que hemos creado (es decir, las
variables de nuestro tipo) y con los mtodos (es decir, con las dos funciones que habamos
definido en el mdulo de clase). En este caso la operacin es mostrar un MsgBox con la
informacin pertinente.

15
Vistame en http://siliconproject.com.ar/neckkito/
7.- Finalizado el proceso, borramos todos los elementos de la coleccin para dejarla vaca.

Si hubiramos querido incluso eliminar la coleccin en s


hubiramos aadido, justo antes del End Sub, la lnea de
cdigo:

Set colMisVehic = Nothing

Fcil, no? Je, je... (nimo, que con un poco de prctica


esto est hecho!).

UTILIZANDO LAS PROPIEDADES: PROCEDIMIENTO PROPERTY


Y ahora que os he machacado con un montn de cdigo es cuando os digo: vamos a
modificarlo con una cosa nueva

La pregunta que nos podra dar origen a esta explicacin es: qu pasa si el valor asignado a
capacidad del depsito de combustible no es correcta? Es decir, que, por error, introducimos
una capacidad de 10000 litros (que yo sepa, no hay ningn vehculo, dentro de los tipos de
vehculos sobre los que estamos trabajando, que pueda tener un depsito as: habra ms
depsito que vehculo!).

Para realizar un control de este elemento podramos utilizar el procedimiento PROPERTY

Para que nos entendamos, y hablando en trminos generales, un procedimiento PROPERTY


vendra a ser un procedimiento que gestiona las caractersticas de una propiedad de nuestra
clase y, por extensin, gestiona los errores (en el sentido de introducciones errneas de
valor) que pudieran producirse.

Tambin nos permite que una propiedad de una clase adopte un comportamiento determinado
en funcin de los parmetros que reciba.

PROPERTY LET
Mediante la instruccin PROPERTY LET generamos el cdigo encargado de gestionar las
caractersticas de la propiedad del elemento definido en la clase.

En abstracto, lo que hara esta instruccin sera:

Public Property Let


'Si pasa esto haz esto
'Si pasa aquello haz esto otro
'Si pasa eso haz eso otro
End Property

Como vemos, podramos equipararlo a un procedimiento SUB por su estructura.

PROPERTY GET
Para poder obtener el valor asignado a la propiedad utilizaremos la instruccin PROPERTY GET.

16
Vistame en http://siliconproject.com.ar/neckkito/
Hablando en abstracto, podramos comparar un PROPERTY GET con una funcin, dado que
devuelve un valor.

Su estructura sera:


Public Property Get nombre(argumentos) As <tipo>
'Codigo
End Property

PROPERTY SET
Podemos asignar una propiedad mediante el property set. En este caso me remitir a la ayuda
de Access, que indica que utilizamos el PROPERTY SET para asignar una referencia a un objeto.

Podramos hacerlo siguiendo la siguiente estructura:

Public Property Set nombre(variableX As Objeto)


Set variableY = variableX
End Property

APLIQUEMOS EL PROCEDIMIENTO PROPERTY


A efectos de ser ms claro voy a realizar de nuevo todo el proceso anterior, bautizndolo
ahora, para que nos entendamos, como clsVehic2. Si queris modificar vuestro cdigo anterior,
pues perfecto, y si queris crearlo de nuevo, pues tambin perfecto: as practicaremos y
afianzaremos el estudio de las clases.

Manos a la obra...

Vamos a suponer que no hay vehculo (de los nuestros) que pueda tener un depsito superior
a los 500 litros. Aprovecharemos para comprobar tambin que no se nos haya colado un
depsito con capacidad negativa. El resto de elementos del cdigo sern los mismos.

Creamos un mdulo de clase, y lo llamaremos clsVehic2.

En ese nuevo mdulo de clase escribimos el siguiente cdigo (ojo, marco en negrita lo nuevo;
el resto es como ya lo habamos escrito en el ejemplo del apartado anterior):

Option Compare Database


Option Explicit

Const capacidadMax As Double = 500 'Defino la capacidad mxima


Private p_capacDep As Double 'Nueva variable que hace referencia a la propiedad
'que gestionaremos con Property Let. Ojo que es <Private>
Public claseVehic As String 'Si es coche, moto o camin
Public nombre As String 'Nombre del vehculo (v.gr., Porshe)
Public tipo As String 'Tipo del vehculo (v.gr., Carrera)
Public cilindrada As Long 'Cilindrada

Public Property Let capacDep(ByVal capacidad As Double)


'Analizamos los supuestos

17
Vistame en http://siliconproject.com.ar/neckkito/
Select Case capacidad
'Si la capacidad es superior a 500 litros
Case Is > capacidadMax
Err.Raise 666, "clsVehic2", "La capacidad del depsito de
combustible no es real"
'Si la capacidad es negativa
Case Is < 0
Err.Raise 667, "clsVehic2", "La capacidad del depsito no
puede ser menor que cero"
Case Else
'Si no el valor es considerado correcto
p_capacDep = capacidad
End Select
End Property

Public Property Get capacDep() As Double


capacDep = p_capacDep
End Property

Public Function nomVehic() As String


nomVehic = nombre & " " & tipo
End Function

Public Function costeDeposito(ByVal precioLitro As Double) As Currency


costeDeposito = capacDep * precioLitro
If costeDeposito > 150 Then
MsgBox "Qu caro! Mejor dejar el vehculo aparcado!", vbExclamation, "UFFF"
End If
End Function

Fijmonos en las principales diferencias:

La propiedad capacDep ahora ya no es una variable (Public capacDep As Double


'Capacidad del depsito, en litros), sino que viene gestionada por nuestro procedimiento
Property (Public Property Let capacDep(ByVal capacidad As Double))

La variable que nos hace de puente entre Property Let y Property Get la hemos
llamado p_capacDep, pero, atencin, la hemos definido como Private, para que su
mbito de actuacin sea slo a nivel de clase (es decir, que no es accesible desde otros
mdulos).

La operacin puente es la siguiente:


Property Let gestiona el valor de la variable <capacidad>, pasada como argumento
en el propio procedimiento ((ByVal capacidad As Double)). Si no hay motivo de error
p_capacDep toma el valor de <capacidad> ('Si no el valor es considerado
correcto
p_capacDep = capacidad)
Property Get asigna el valor de nuestra propiedad de clase a p_capacDep, de
manera que si esta tiene valor significa que todas las comprobaciones han sido
correctas (capacDep = p_capacDep)

Y fijmonos tambin que, si se incumple alguna de las condiciones, generamos nuestros


propios errores a travs de4

Err.Raise 666, "clsVehic2", "La capacidad del depsito de combustible no es real"


Err.Raise 667, "clsVehic2", "La capacidad del depsito no puede ser menor que cero"

Sigamos: debemos crearnos un nuevo mdulo estndar para generar la coleccin que nos dar
la informacin de nuestros vehculos. A este nuevo mdulo lo llamaremos mdlVehic2. Para
simplificar slo rellenaremos un vehculo por tipo y los listaremos, sin pedir otra cosa al usuario

4 Para refrescar memorias podis consultar el captulo 13 de este curso

18
Vistame en http://siliconproject.com.ar/neckkito/
que el precio del combustible.

El cdigo de ese nuevo mdulo debera ser:


Option Compare Database
Option Explicit

'Declaramos una coleccin


Public colMisVehic As Collection

Public Sub misVehiculos2()


'Definimos la coleccin
Set colMisVehic = New Collection
'Declaramos un objeto perteneciente a nuestra clase
Dim unVehiculo As clsVehic2
'Declaramos una variable que recoger los elementos de la coleccin, y
'que tambin pertenecer a nuestra clase
Dim elemVehic As clsVehic2
'Creamos una instancia del objeto unVehiculo
Set unVehiculo = New clsVehic2
'Rellenamos los datos que necesitamos
With unVehiculo
.claseVehic = "Coche"
.nombre = "Porshe"
.tipo = "Carrera"
.cilindrada = 3000
.capacDep = 80.5
End With
'Lo aadimos a nuestra coleccin
colMisVehic.Add unVehiculo, "PorCar"
'Rellenamos el siguiente vehculo
Set unVehiculo = New clsVehic2
With unVehiculo
.claseVehic = "Moto"
.nombre = "Suzuki"
.tipo = "Bandid"
.cilindrada = 650
.capacDep = 30.3
End With
colMisVehic.Add unVehiculo, "SuzBan"
'Rellenamos el siguiente vehculo
Set unVehiculo = New clsVehic2
With unVehiculo
.claseVehic = "Camin"
.nombre = "Mercedes"
.tipo = "Pegaso"
.cilindrada = 4000
.capacDep = 120.7
End With
colMisVehic.Add unVehiculo, "MerPeg"
'Por simplificar suponemos que todos utilizan el mismo tipo de combustible
Dim vPrecioCombustible As Variant
vPrecioCombustible = InputBox("Introduzca el precio por litro de combustible", "PRECIO")
'Tambin, por simplificar, no introduzco elementos de control para el valor introducido
'Si quisirais utilizarlos os podis guiar por los elementos de control que he utilizado
'en el primer InputBox
If StrPtr(vPrecioCombustible) = 0 Then GoTo BorraColeccion
'Procedemos a la enumeracin de los vehculos
For Each elemVehic In colMisVehic
MsgBox "El vehculo tiene las siguientes caractersticas:" & vbCrLf & vbCrLf _
& "Clase: " & elemVehic.claseVehic & vbCrLf _
& "Nombre: " & elemVehic.nomVehic & vbCrLf _
& "Cilindrada: " & elemVehic.cilindrada & vbCrLf _
& "Capacidad del depsito: " & elemVehic.capacDep & vbCrLf _
& "Precio de llenado del depsito: " & elemVehic.costeDeposito(vPrecioCombustible), _
vbInformation, "DATOS"
Next elemVehic
'Borramos los elementos de la coleccin

19
Vistame en http://siliconproject.com.ar/neckkito/
BorraColeccion:
Dim i As Long
For i = colMisVehic.Count To 1 Step -1 'Realizamos una cuenta atrs
colMisVehic.Remove (i)
Next i
End Sub

Si finalmente creamos en un formulario un botn de


comando deberemos asignarle una llamada al
procedimiento misVehiculos2 con este simple cdigo:

Private Sub cmdListaVehicProperty_Click()


Call misVehiculos2
End Sub

Si hacemos click sobre ese botn (con el formulario en vista formulario) se nos solicitar el
precio del litro de combustible y nos enumerar, a travs de MsgBox, nuestros vehculos con
sus caractersticas.

Si ahora modificamos la capacidad del depsito de nuestro Porshe (la idea es que nos
equivocamos involuntariamente al determinar dicha capacidad) y escribimos:


With unVehiculo
.claseVehic = "Coche"
.nombre = "Porshe"
.tipo = "Carrera"
.cilindrada = 3000
.capacDep = 800.5
End With

la ejecucin de nuestro cdigo nos devolver lo siguiente:

De la misma manera, si escribimos

.capacDep = -80.5

Obtendremos el siguiente mensaje:

20
Vistame en http://siliconproject.com.ar/neckkito/
UNAS BREVES EXPLICACIONES TERICAS BASADAS EN TODO LO
ANTERIOR
Para profundizar en el marco terico en base al ejemplo anterior vamos a ponernos metafsicos
y vamos a hablar del alma y del cuerpo. Me vais a permitir esta pequea licencia porque me
viene que ni pintada para que podamos entender lo que os quiero transmitir. Adems, quin
os iba a decir que la religin servira para explicar VBA?5

Supongamos que existe una esencia universal (llammosle Dios, el Uno, el Todo...), y
supongamos que una persona humana, al nacer, est compuesto por un cuerpo fsico y un
alma que, en realidad, es una parte de dicha esencia universal. Es decir, que dicha alma es
individualizable pero al mismo tiempo es parte de un Todo.

Pues bien, nuestra clase sera esa esencia universal. A partir de ah podemos crear las
personas (=objetos) que necesitemos. Si yo creo el objeto <miVehiculo> y creo el objeto
<tuVehiculo> el cuerpo fsico de <miVehiculo> es diferente y diferenciable de <tuVehiculo>,
pero sus almas, aunque diferentes, son partes de una esencia universal (= clase).

<miVehiculo> y <tuVehiculo> se denominan, en jerga informtica, ejemplares de clase.

Bajemos un nivel: mi cdigo VB y yo tomamos una gran decisin: vamos a tener un hijo. A
este hijo le vamos a poner de nombre <elHijoVehculo>.

La pregunta que nos hacemos en este punto es: existe <elHijoVehculo>? Y la respuesta es:
s existe a nivel mental, porque mi cdigo y yo as lo hemos decidido, pero an no existe a
nivel fsico porque an no ha sido concebido.

Y por fin vamos a poner sobre la mesa y en conjuncin todo este planteamiento con lo que
acabamos de programar en el ejemplo anterior:

1.- Creamos la esencia universal Eso se refleja en la creacin de la clase (creacin del
mdulo de clase).

2.- Decidimos tener un hijo Eso se refleja en la declaracin de la variable.

Dim elHijoVehiculo As clsVehic

En este momento <elHijoVehiculo> no es nada. Siguiendo el smil, es la expresin de un


deseo.

5 Os ruego que tomis esta explicacin nicamente como lo que es: una explicacin. En ningn momento pretendo entrar en
valoraciones, ni crticas, ni desprecios, ni comparaciones. Al contrario, estos temas merecen todo mi respeto. Por favor, que nadie
le busque cinco pies al gato porque lejos de m est actuar con un nimo negativo, sino ser lo ms claro posible en la explicacin.

21
Vistame en http://siliconproject.com.ar/neckkito/
3.- Concebimos <elHijoVehculo> Eso se produce cuando hacemos

Set elHijoVehiculo = New clsVehic

Pero mucho cuidado: si en ese momento nos mezclan


nuestro recin nacido con otros bebs no vamos a ser
capaces de decir Este es el mo!. Nos hace falta algo,
verdad?

4.- Nos fijamos en los rasgos de nuestro hijo para saber


que es nuestro Eso se produce cuando definimos las
propiedades (me vais a permitir la licencia de inventarme
dichas propiedades simplemente para que queden mejor
en el ejemplo).

With elHijoVehiculo
.Pelo = Peln
.Nariz = Como la del padre
.Peso = 3 Kg
.Lloro = Muy llorn
End With

En definitiva, que a travs de todo lo anterior ya deberamos tener muy claro todo el proceso y,
si nos falla algo, tendremos una gua de pasos para detectar en qu fase podra estar el
error.

Sigamos un poco ms. Si os fijis en el cdigo, en la parte repetitiva con el comentario

'Rellenamos el siguiente vehculo


Set unVehiculo = New clsVehic
With unVehiculo

Veris que en cada adicin estamos escribiendo la lnea de cdigo:

Set unVehiculo = New clsVehic

Por qu es necesario escribirla?

Imaginemos que yo tengo una clase, clsBebe, y defino un ejemplar de clase as:

Set miBebe = New clsBebe

y le asigno valores a las propiedades:

With miBebe
.Caracter = Dulce
.Ojos = Llorones
End with

Ya tenemos a miBebe definido. A continuacin creo otro miBebe:

Caso A: rellenando directamente las propiedades (sin el Set miBebe = New clsBebe)

With miBebe

22
Vistame en http://siliconproject.com.ar/neckkito/
.Caracter = Grun
.Ojos = Desafiantes
End with

Caso B: rellenando las propiedades pero antes pasando por


el Set

Set miBebe = New clsBebe


With miBebe
.Caracter = Grun
.Ojos = Desafiantes
End with

Qu hemos obtenido en realidad segn el caso?

Caso A NO hemos obtenido otro beb, sino que lo que hemos hecho es mostrar mi beb en
su adolescencia

Caso B S hemos obtenido otro beb.

Es decir, que en el caso A no hemos creado uno nuevo, sino que, en el mismo beb, hemos
cambiado sus propiedades.

En el caso B tenamos un beb; a continuacin este ya ha dejado de existir para ser sustituido
por otro miBebe, con otras propiedades diferentes.

Vemos la diferencia?

Para mayor abundamiento os propongo que en el cdigo anterior (en el procedimiento Public
Sub misVehiculos) convirtis en comentarios todos los <Set unVehiculo = New clsVehic>,
exceptuando el primero, y ejecutis el cdigo. As podris ver qu grata sorpresa nos llevamos.

UN EJEMPLO INTEGRNDOLO CON ACCESS


Desarrollemos un ejemplo con todo lo anterior, integrndolo con informacin que tengamos
almacenada en Access. En este ejemplo no utilizar las colecciones porque creo que con lo
explicado anteriormente deberamos tenerlo claro. Digamos que le dar un enfoque diferente.

Dado que quiz ya entremos en terrenos algo complejos os recomiendo que no slo analicis
los cdigos que vendrn, sino tambin cmo se realiza el planteamiento del problema. Ni que
decir tiene que si el cdigo es tcnicamente perfecto pero el problema no est bien planteado y
planificado los resultados no van a ser satisfactorios.

He aqu el problema:

<<Nuestra empresa es una empresa de alquiler de coches. En nuestra flota de automviles


tenemos una serie de modelos que se adaptan a unas caractersticas que nosotros hemos
generalizado. La idea es que nuestro cliente que venga a alquilar un coche pueda elegir una
combinacin de esas caractersticas y, en un momento, podamos darle a escoger una serie de
vehculos que cumplan dichas caractersticas, a la vez que le proporcionamos informacin
complementaria actualizada que puede ser de mucho inters>>

Vayamos analizando los elementos de que disponemos al tiempo que creamos nuestras tablas
en Access.

En primer lugar, crearemos una tabla que nos recoger los modelos y las caractersticas que

23
Vistame en http://siliconproject.com.ar/neckkito/
necesitamos. A esa tabla la llamaremos TAutos. Tendr la siguiente estructura (algunos
campos se podran haber desglosado en dos o ms, pero los he unificado a efectos de
simplificar al mximo y no hacer el ejemplo engorroso en demasa):

Fijaos que para los campos [GamaAuto], [TerrenoAuto] y [TipoCombAuto] lo ideal hubiera sido
crearnos tablas auxiliares con la informacin, y que nuestra TAuto hubiera chupado los datos
de dichas tablas auxiliares. Sin embargo, a efectos de simplificacin, nosotros escribiremos los
valores directamente.

Apunto lo anterior para que lo tengis en cuenta de cara a vuestras BD's.

Rellenamos TAutos con algunos datos6; por ejemplo, as:

Hagamos notar que el consumo medio se refiere al consumo en litros cada 100 kilmetros (por
si no quedaba claro qu significaba ese valor).

Avancemos un poco los acontecimientos:

Nuestro cliente va a decidir qu gama de coche desea Recurriremos a [GamaAuto]


Nuestro cliente va a decidir en qu tipo de terreno va a utilizar el coche Recurriremos
a [TerrenoAuto]
Nuestro cliente nos va a informar de cuntos kilmetros prev realizar Sabemos qu
combustible utiliza el coche ([TipoCombAuto]) y cul es su consumo medio por
kilmetro ([ConsumMedAuto]) Recurriremos a una tabla auxiliar donde informaremos
del precio por litro de combustible, y algn trabajador nuestro actualizar la tabla en
cuanto se produzcan modificaciones en dichos precios.
El precio de alquiler incluye ya seguro. Sin embargo, ofreceremos al cliente la
posibilidad de efectuar el pago de una sobreprima de seguro, que ir en funcin de la
gama del auto, y que ofrecer coberturas extras (que la poltica de empresa decidir en
funcin de lo que haya negociado con la compaa aseguradora) Requeriremos de
una tabla auxiliar que nos relacione la gama con el precio de la sobreprima.
El precio del alquiler ir en funcin de la gama del vehculo y de los das de alquiler.
6 Los datos que veris son totalmente inventados. No tomis estos datos como datos de la vida real.

24
Vistame en http://siliconproject.com.ar/neckkito/
Nuestro cliente nos indicar cuntos das va a necesitar el vehculo Requeriremos de
una tabla auxiliar que nos d los precios por da, segn la gama, y que un trabajador
nuestro actualizar tan pronto como la empresa decida modificar esos
precios.

Con lo anterior ya podemos empezar a vislumbrar qu


necesidades tenemos, verdad? Empecemos pues por
crearnos nuestras tablas auxiliares.

Crearemos la tabla TPrecioComb, que tendr la siguiente


estructura:

Y la rellenaremos con los siguientes datos:

Crearemos la tabla TPrimas con la siguiente estructura:

Y la rellenaremos con los siguientes datos:

Crearemos la tabla TPrecios con la siguiente estructura:

Y rellenaremos los datos as:

25
Vistame en http://siliconproject.com.ar/neckkito/
Espero que, hasta aqu, no nos hayamos perdido... je, je...

Vamos a la siguiente fase, que ser crearnos la clase.


Insertamos pues un nuevo mdulo de clase que llamaremos
clsAutos.

Veris que he programado un procedimiento PROPERTY para comprobar que no pueda haber
un consumo medio negativo o igual a cero.
Eso lo podra haber controlado a travs del campo [ConsumMedioAuto] de la tabla TAutos, con
una regla de validacin, pero como la idea es practicar las clases lo controlaremos desde aqu.

Las explicaciones estn como comentarios en el propio cdigo.

Y, por fin, el cdigo de clsAuto nos queda as:

Option Compare Database


Option Explicit

'Declaramos las variables


Private p_consumMedio As Double
Public nombreCoche As String
Public gamaCoche As String
Public terrenoCoche As String
Public tipoCombCoche As String

'Controlamos que el consumo medio no sea negativo ni cero


Public Property Let consumMedioCoche(ByVal consumoMedio As Double)
'Analizamos los supuestos
If consumoMedio <= 0 Then
Err.Raise 666, "clsAuto", "El consumo medio no puede ser negativo o cero"
Else
p_consumMedio = consumoMedio
End If
End Property

'Obtenemos el valor del valor puente ya depurado


Public Property Get consumMedioCoche() As Double
consumMedioCoche = p_consumMedio
End Property

'Establecemos el coste del alquiler segn los das requeridos


Public Function alquilerCoche(numDias As Integer, precioDiario As Currency) As Currency
alquilerCoche = numDias * precioDiario
End Function

'Establecemos el coste de la sobreprima


Public Function sobreprimaCoche(importePrima As Currency, numDias As Integer) As Currency
sobreprimaCoche = (importePrima * numDias) * 10 / 365
End Function

'Establecemos el coste previsto en gasolina


Public Function gasolinaCoche(numKilometros As Long, precioComb As Currency) As Currency
gasolinaCoche = (p_consumMedio / 100) * numKilometros * precioComb
End Function

Como vemos, nuestra clase recoger toda la informacin que queremos proporcionar al cliente.

26
Vistame en http://siliconproject.com.ar/neckkito/
Para clarificar ideas digamos que:

El procedimiento Property (Let y Get) comprueba


consumMedioCoche
alquilerCoche nos proporciona el precio total del alquiler
sobreprimaCoche nos proporciona el importe de esa prima
adicional. Obviamente la frmula me la he inventado, no es
ninguna receta mgica
gasolinaCoche nos proporciona el consumo en funcin del
consumo por kilmetro, del nmero de kilmetros y el
precio por litro de carburante.

Siguiente fase: creemos un mdulo estndar. A ese mdulo estandar lo llamaremos mdlAuto.
Qu va a hacer ese mdulo? Lo que va a hacer es un doble proceso, adornado con algunas
operaciones adicionales:

Uno: va a recoger toda la informacin de nuestra tabla TAutos y nos va a rellenar los datos
correspondientes a la clase

Dos: va a plasmar esos datos en una tabla temporal, para tener una base donde filtrar segn
las necesidades del cliente y a travs de la cual podremos preparar un informe para
entregrselo a nuestro seguro consumidor.

El cdigo de ese mdulo ser el siguiente:

Option Compare Database


Option Explicit

'Requiere tener registrada la referencia "Microsoft DAO 3.6 Object Library" o


'mdulo equivalente----------------------------------------------------------

'Declaramos las variables del mdulo


Private Const nomTablaAux As String = "TAuxInfoCliente"
Private dbs As DAO.Database
Private rstIN As DAO.Recordset
Private rstOUT As DAO.Recordset
Private tbl As Object
Private miSql As String
Private miCoche As clsAuto
Private buscoPrecioComb As Currency
Private buscoPrima As Currency
Private buscoPrecioAlquiler As Currency

'Creamos el procedimiento que nos generar la tabla


Public Sub creoTAux(numKm As Long, diasAlq As Integer)

'Creo un control de errores por si se produce algn error inesperado


On Error GoTo sol_err

'Defino la BD de trabajo
Set dbs = CurrentDb
'En primer lugar debemos comprobar si la tabla ya existe. Si existe debemos
'borrarla para que no nos d error de cdigo
For Each tbl In CurrentData.AllTables
If tbl.Name = nomTablaAux Then
DoCmd.DeleteObject acTable, nomTablaAux
Exit For
End If
Next tbl
'Creamos la estructura de la tabla a travs de una SQL. La escribo estructurada
'en lneas para que apreciemos perfectamente los campos que se crearn
'Para relacionarlo con el cdigo posterior, tened en cuenta que:

27
Vistame en http://siliconproject.com.ar/neckkito/
'Nombre -> Ser el Field(0); Gama -> Ser el Field(1); ... ; PrecioAlquiler ->
'Ser el Field(6)
miSql = "CREATE TABLE " & nomTablaAux & " (" _
& "Nombre STRING," _
& "Gama STRING," _
& "Terreno STRING," _
& "TipoCombustible STRING," _
& "PrevGtoComb CURRENCY," _
& "Sobreprima CURRENCY," _
& "PrecioAlquiler CURRENCY" _
& ")"
'Creamos la tabla a travs de la ejecucin de la SQL
dbs.Execute miSql

'Defino los recordset


Set rstIN = dbs.OpenRecordset("TAutos", dbOpenForwardOnly)
Set rstOUT = dbs.OpenRecordset("TAuxInfoCliente", dbOpenTable)
'Aqu el proceso va a ser doble: vamos a recorrer los registros de TAutos. Situados
'en un registro concreto, vamos a crear los elementos de la clase. Una vez creados
'los vamos a traspasar a nuestra tabla auxiliar
With rstIN
Do Until .EOF
'Creo un ejemplar de clase
Set miCoche = New clsAuto
'Relleno los datos 'fijos' con la informacin del registro
miCoche.nombreCoche = .Fields("NomAuto").Value
miCoche.gamaCoche = .Fields("GamaAuto").Value
miCoche.terrenoCoche = .Fields("TerrenoAuto").Value
miCoche.tipoCombCoche = .Fields("TipoCombAuto").Value
miCoche.consumMedioCoche = .Fields("ConsumMedAuto").Value
'Obtengo el origen de los datos variables buscando en las tablas auxiliares
buscoPrecioComb = DLookup("[ImpComb]", "TPrecioComb", "[TipoComb]='" _
& miCoche.tipoCombCoche & "'")
buscoPrima = DLookup("[Prima]", "TPrimas", "[GamaPrima]='" _
& miCoche.gamaCoche & "'")
buscoPrecioAlquiler = DLookup("[Precio]", "TPrecios", "[GamaPrec]='" _
& miCoche.gamaCoche & "'")
'Paso los datos a la tabla auxiliar
rstOUT.AddNew
rstOUT.Fields(0).Value = miCoche.nombreCoche
rstOUT.Fields(1).Value = miCoche.gamaCoche
rstOUT.Fields(2).Value = miCoche.terrenoCoche
rstOUT.Fields(3).Value = miCoche.tipoCombCoche
rstOUT.Fields(4).Value = miCoche.gasolinaCoche(numKm, buscoPrecioComb)
rstOUT.Fields(5).Value = miCoche.sobreprimaCoche(buscoPrima, diasAlq)
rstOUT.Fields(6).Value = miCoche.alquilerCoche(diasAlq, buscoPrecioAlquiler)
rstOUT.Update
.MoveNext
Loop
End With
Salida:
'Cerramos conexiones y liberamos memoria
rstIN.Close
rstOUT.Close
dbs.Close
Set rstIN = Nothing
Set rstOUT = Nothing
Set dbs = Nothing
Exit Sub
sol_err:
MsgBox "Se ha producido el error " & Err.Number & " - " & Err.Description & vbCrLf & vbCrLf _
& "El origen del error est en " & Err.Source
Resume Salida
End Sub

Fijaos en cmo se me ha ocurrido articular el proceso: como un obrero en medio de dos cintas
de montaje: por una de las cintas (rstIN) llega un paquete (la tabla TAutos), nuestro obrero (la
clase) le pone los lacitos para dejarlo guapo y lo deposita sobre la otra cinta (rstOUT) listo

28
Vistame en http://siliconproject.com.ar/neckkito/
para servir.

Como curiosidad cabe remarcar que en el control de errores


he aadido que el mensaje nos muestre el origen del error
a travs de Err.Source, dado que se manejan bastantes
elementos. Ello nos ayudar a depurar el error, si se
produce, con mayor facilidad.

Como podemos ver, nuestro mdulo se ha simplificado


bastante en cuanto a clculos porque dichos clculos ya los
hemos establecido a travs de mtodos en nuestra clase.
As, hemos podido realizar las siguientes acciones:

...
'Relleno los datos 'fijos' con la informacin del registro
...

para dichos datos 'fijos', y con los datos variables hemos necesitado, simplemente recuperar el
valor de los argumentos a travs de las variables buscoXXX y pasrselos al mtodo, a travs
de las lneas

'Obtengo el origen de los datos variables buscando en las tablas auxiliares


buscoPrecioComb = DLookup("[ImpComb]", "TPrecioComb", "[TipoComb]='" _
& miCoche.tipoCombCoche & "'")
buscoPrima = DLookup("[Prima]", "TPrimas", "[GamaPrima]='" _
& miCoche.gamaCoche & "'")
buscoPrecioAlquiler = DLookup("[Precio]", "TPrecios", "[GamaPrec]='" _
& miCoche.gamaCoche & "'")

rstOUT.Fields(4).Value = miCoche.gasolinaCoche(numKm, buscoPrecioComb)


rstOUT.Fields(5).Value = miCoche.sobreprimaCoche(buscoPrima)
rstOUT.Fields(6).Value = miCoche.alquilerCoche(diasAlq, buscoPrecioAlquiler)

Tambin fijaos en que los datos externos, que deben ser proporcionados por nuestro cliente
(previsin de kilmetros a recorrer y das que quiere alquilar el vehculo) y que, lgicamente,
no sabemos a priori, los paso como argumentos del procedimiento, a travs de

Public Sub creoTAux(numKm As Long, diasAlq As Integer)

Sigamos: para el proceso que sigue vamos a necesitar que la tabla auxiliar TAuxInfoCliente
est creada. Para ello creamos, en el mismo mdulo de trabajo mdlAuto, un procedimiento que
eliminaremos tras su ejecucin (o, si no queremos eliminarlo, podemos convertir en
comentario), y que ser el mismo del cdigo anterior con unas ligersimas modificaciones
(prcticamente es un copy-paste de un fragmento del cdigo anterior; os marco en negrita lo
que se debe cambiar, que est hacia el final del cdigo):

29
Vistame en http://siliconproject.com.ar/neckkito/
Private Sub creoTablaPorPrimeraVez()
'Creamos la estructura de la tabla a travs de una SQL.
miSql = "CREATE TABLE " & nomTablaAux & " (" _
& "Nombre STRING," _
& "Gama STRING," _
& "Terreno STRING," _
& "TipoCombustible STRING," _
& "PrevGtoComb CURRENCY," _
& "Sobreprima CURRENCY," _
& "PrecioAlquiler CURRENCY" _
& ")"
'Creamos la tabla a travs de la ejecucin de la SQL
CurrentDb.Execute miSql
End Sub

Nos situamos sobre ese Sub y pulsamos F5. Nuestra tabla se crear. Ya podemos borrar el
cdigo, o convertirlo en comentario. Tened en cuenta que:

Si la tabla ya existe nos dar error de cdigo


Puede ser que no veamos la tabla creada en Access. Si es as seleccionad cualquier
tabla y pulsad F5 para actualizar. La tabla recin creada nos aparecer de la nada.

Vamos a crearnos un informe sobre la tabla TAuxInfoCliente, y lo llamaremos RAuxInfoCliente.


Eso no tiene mayor complicacin ya para nosotros.

Y ya llegamos a la fase en el que el usuario tendr una participacin activa. Vamos a crearnos
un formulario en blanco que llamaremos FInfoCliente. Yo lo crear con TextBox para simplificar,
pero lgicamente ya sabramos crear otros controles, como cuadros combinados o cuadros de
lista, para hacerlo ms atractivo y eficiente de cara al usuario. Lo que haremos ser lo
siguiente:

Insertar un textBox, que llamaremos txtGama


Insertar un textBox, que llamaremos txtTerreno
Insertar un textBox, que llamaremos txtKm
Insertar un textBox, que llamaremos txtDiasAlq
Insertar un botn de comando, que llamaremos cmdAbreRAuxInfoCliente

En definitiva, una cosa as:

30
Vistame en http://siliconproject.com.ar/neckkito/
Por cierto, y por si alguien no lo sabe, para establecer el texto de la ayuda contextual debemos
ir a las propiedades del control Otras Texto de Ayuda del control

El cdigo que debemos asignar al botn de comando ser el


siguiente (ojo: no pondr ningn control para validar la
introduccin de los valores para simplificar el cdigo;
vosotros ya deberais saber qu lneas de cdigo os
serviran para controlar eso):


Private Sub cmdAbreRAuxInfoCliente_Click()
'Declaramos las variables
Dim vGama As String, vTerreno As String
Dim vKm As Long, vDias As Integer
Dim filtroDeseosCliente As String
'Asignamos valor a las variables
vGama = Me.txtGama.Value
vTerreno = Me.txtTerreno.Value
vKm = Me.txtKm.Value
vDias = Me.txtDiasAlq.Value
'Llamamos al procedimiento creoTAux, asignndole los parmetros requeridos
Call creoTAux(vKm, vDias)
'Creo el filtro para abrir el informe
filtroDeseosCliente = "[Gama]='" & vGama & "' AND [Terreno]='" & vTerreno & "'"
'Abro el informe, filtrndolo por las peticiones del cliente
DoCmd.OpenReport "RAuxInfoCliente", acViewPreview, , filtroDeseosCliente
End Sub

Y creo que ya est. Esta vez no dir aquello de... fcil, verdad?

PARA FINALIZAR ESTE CAPTULO


Las clases tambin nos permiten definir eventos (usaramos EVENT), llamar a dichos eventos
(tenemos para ello el RAISE EVENT), y algunas cosillas ms. Sin embargo, vamos a pararnos
aqu. Creo que ya tenemos bastante material para programar nuestras BD's.

Alguien me podra objetar: para desarrollar este ltimo ejemplo se podran haber utilizado
otros mtodos, y quiz no tan complicados, y yo dir: Totalmente de acuerdo... si slo nos
centramos en el ejemplo. Pero la gracia de lo anterior es que nuestra futura aplicacin no es
slo darle la informacin que hemos comentado al cliente, sino que, hipotticamente, la BD
nos servira para gestionar nuestro negocio. Y la pregunta es: Si, por ejemplo, tenemos que
emitir una factura al cliente, deberamos volver a calcular todo de nuevo mediante cdigo? O,
si por ejemplo, un histrico nos muestra una media de das que se alquila un coche de una
determinada gama, y una media de kilmetros que realiza dicho automvil, y queremos sacar
una previsin de cara al ao siguiente, debemos volver a realizar por tercera vez todos los
clculos? No es mejor tener los clculos y datos clave recogidos en nuestra clase, y acceder
a ella cuando los necesitemos? Porque as slo necesitamos programar dichos clculos una sola
vez, no es cierto?

Ms alla, podemos exportar la estructura bsica de la BD (tablas) y mdulos de clase y


estndar, e importarlos en otra BD a la que queramos dar otra utilidad. Con ello todo el trabajo
de programacin, en lo que a estos elementos se refiere, ya lo tenemos hecho, y si hay que
adaptarlo no debera suponernos el mismo trabajo que empezar de cero.

En fin... que creo que, segn cmo sea nuestro proyecto, la utilizacin de clases es un recurso

31
Vistame en http://siliconproject.com.ar/neckkito/
muy til... y ahora ya sabemos cmo manejarlo.

Espero que lo que hayis podido aprender de este captulo os sea til.

Un saludo y...

suerte!

32
Vistame en http://siliconproject.com.ar/neckkito/

You might also like