Documentos de Académico
Documentos de Profesional
Documentos de Cultura
CAPÍTULO 181
Índice de contenido
TIPOS, COLECCIONES Y CLASES..................................................................................................2
INTRODUCCIÓN...........................................................................................................................2
TIPOS..............................................................................................................................................2
COLECCIONES..............................................................................................................................6
DEFINIR UNA COLECCIÓN....................................................................................................6
AÑADIR ELEMENTOS A UNA COLECCIÓN........................................................................7
CONTAR ELEMENTOS DE UNA COLECCIÓN....................................................................7
ELIMINAR ELEMENTOS DE UNA COLECCIÓN.................................................................7
RECORRER LOS ELEMENTOS DE UNA COLECCIÓN.......................................................8
UN EJEMPLO CON TODO LO ANTERIOR............................................................................8
CLASES...........................................................................................................................................9
TRABAJANDO CON LAS CLASES...........................................................................................11
EXPORTANDO EL MÓDULO 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 TEÓRICAS BASADAS EN TODO LO ANTERIOR. 21
UN EJEMPLO INTEGRÁNDOLO CON ACCESS.....................................................................23
PARA FINALIZAR ESTE CAPÍTULO........................................................................................31
1
Visítame en http://bit.ly/NckAccess
TIPOS, COLECCIONES Y CLASES
INTRODUCCIÓN
El objetivo de este capítulo 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 (lógicamente) las ideas que subyacen en cada uno
de ellos nos allanarán el camino para llegar a las clases.
Es por esto por lo que empezaremos desarrollando los que son los tipos, cómo se definen, etc.,
y haremos lo mismo con las colecciones (que, además, ya nos debería “sonar de algo” si
hemos seguido todo este curso hasta aquí).
Como utilizaremos los conceptos explicados cuando hablábamos de matrices, si notáis que
tenéis un momento de “debilidad memorística”, quizá sería interesante que tuvierais a mano el
capítulo 9, donde se habla de ellas.
Os advierto que este capítulo quizá pueda resultaros algo complejo, sobre todo en la parte
final del mismo y en especial en el apartado “Un ejemplo integrándolo con Access”,
básicamente porque se mezclan no sólo cosas de este capítulo sino elementos que hemos ido
explicando (y aprendiendo, supongo ) durante este curso. Pensad que la finalidad es
podernos construir nuestro propio módulo de clase (todo un “lujazo” para nuestra aplicación).
Empecemos pues.
TIPOS
Nuestro buen amigo Access nos dice, refiriéndose a la instrucción Type, lo siguiente: <<Se usa
en el nivel de módulo para definir un tipo de datos definido por el usuario que contiene uno o
más elementos>>.
• “Se usa a nivel de módulo”. Pues vaya, ya tenemos una primera pista.
• “Tipo de datos”. Sabemos que hay datos numéricos, booleanos, de texto... ¿Qué tipo de
datos será?
• “Definido por el usuario”. Ergo no es un tipo de datos llamémosle “estándar”, sino que
es el usuario el que se lo “saca de la manga”.
• “Contiene uno o más elementos”. Eso me suena a matrices, ¿verdad?
2
Visítame en http://bit.ly/NckAccess
Pues los elementos deben ser definidos dentro de un procedimiento.
Como hemos comentado antes, la definición de los tipos debe ir en la cabecera del módulo
(debajo de Option Compare Database / Option Explicit). Así, los elementos que componen
nuestro tipo serán dos:
…
Public Type CodigoColor
nombre As String * 10
significado As String * 25
End Type
…
Como veis, las variables que indican la definición de los elementos son, en este caso, de tipo
texto String. Además, hemos indicado su longitud máxima (a través de “* 10” y “* 25”).
Como es el primer ejemplo “fácil” sólo vamos a rellenar los datos de un color. Como
comentaba antes, una vez entendido lo que hace nuestro código pondremos un ejemplo más
complejo.
Para rellenar los elementos del tipo vamos a utilizar un procedimiento público, que llamaremos
rellenaCodigos. Lo escribiríamos así, inmediatamente debajo de nuestra definición de tipo
personalizado CodigoColor:
…
Public Sub rellenaCodigos()
'Declaramos una variable, diciéndole que es de nuestro tipo personalizado
Dim vColor As CodigoColor
'Rellenamos los valores
vColor.nombre = "Verde"
vColor.significado = "Sin peligro"
3
Visítame en http://bit.ly/NckAccess
'Mostramos los resultados
MsgBox vColor.nombre & vColor.significado, vbInformation, "DATOS"
End Sub
…
Fijaos en que:
Compliquemos un poco más la cosa. Supongamos que tenemos un listado de países con sus
monedas. El listado que utilizaremos será el siguiente:
1- USA - Dólar
2- España - Euro
3- Japón - Yen
Nos crearemos, en nuestro módulo, un nuevo tipo, al que llamaremos Monedas, de la manera
siguiente:
…
Public Type tipoMoneda
nombre As String * 10
Moneda As String * 10
End Type
…
…
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 = "España"
paisMoneda(3).nombre = "Japón"
paisMoneda(1).moneda = "Dólar"
paisMoneda(2).moneda = "Euro"
paisMoneda(3).moneda = "Yen"
'Devolvemos un MsgBox con la información
MsgBox "El país " & paisMoneda(indice).nombre & " usa la moneda " &
paisMoneda(indice).moneda, _
vbInformation, "RESULTADO"
End Sub
…
4
Visítame en http://bit.ly/NckAccess
Private Sub cmdProcedimientousaMoneda_Click()
'Declaramos las variables
Dim vCod As Variant
'Solicitamos al usuario un código de país
vCod = InputBox("Introduzca código del país (número
del 1 al 3)", "CÓDIGO PAÍS", "1")
'Llamamos al procedimiento usaMoneda()
Call usaMoneda(vCod)
End Sub
…
También pensad que podemos “reutilizar” nuestra definición de tipo para otras acciones (si lo
planificamos bien nos puede salir una definición de tipos bastante “universal”).
Por ejemplo, si creamos otro procedimiento para saber en qué moneda debemos pagar a un
cliente, sabiendo su código de cliente, sólo deberíamos escribir un procedimiento específico
para ello, sin tener que volver a definir otro tipo.
…
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 = "Dólar"
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
…
…
Private Sub cmdProcedimientoclienteMoneda_Click()
'Declaramos las variables
Dim vCod As Variant
'Solicitamos al usuario un código de cliente
vCod = InputBox("Introduzca código del cliente (número del 1 al 3)", "CÓDIGO CLIENTE",
"1")
'Llamamos al procedimiento clienteMoneda()
Call clienteMoneda(vCod)
End Sub
…
Para finalizar, tened en cuenta que hemos utilizado matrices estáticas para definir los índices
de los datos. No habría ningún problema en utilizar matrices dinámicas si no conocemos, de
antemano, el número de elementos que va a haber en la matriz.
5
Visítame en http://bit.ly/NckAccess
COLECCIONES
Durante todo el curso hemos estado viendo, en
determinados capítulos, distintas colecciones. A modo de
recordatorio, hemos visto la colección Fields() de un
recordset, o la colección 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”.
<<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 colección sólo tienen
que estar relacionados por el hecho de existir en la colección. Los miembros de una colección
no tienen que compartir el mismo tipo de dato>>.
Veamos:
Con todo lo anterior ya vemos que podemos crearnos nuestras propias colecciones.
y definirla así:
6
Visítame en http://bit.ly/NckAccess
Nos debería sonar también la idea de que esos dos pasos podemos
resumirlos en uno, declarando la colección de la siguiente manera:
La estructura sería:
nomColección.Add “Elemento”
o bien
Por ejemplo, si yo quiero añadir mi coche “Porshe Carrera” a la colección escribiría lo siguiente:
Si, además, quisiera identificar ese coche con una palabra clave, podría añadirla también con
el ADD. Por ejemplo, supongamos que mi clave para el “Porshe Carrera” es “PorCar”; luego
escribiría:
nomColeccion.Count
Es decir:
misCoches.Count
Los elementos de una colección tienen todos un índice, que vendría a ser el identificador de la
posición que ocupan en la colección. Sabiendo esto, y también sabiendo que podemos eliminar
un elemento por su palabra clave, la estructura para eliminar sería:
nomColeccion.Remove (índice)
o bien
7
Visítame en http://bit.ly/NckAccess
nomColeccion.Remove (“clave”)
misCoches.Remove (6)
o así
misCoches.Remove (“PorCar”)
…
Public Sub colecCoches()
'Declaramos las variables
Dim cocheBorrado As String
'Declaramos la colección
Dim misCoches As Collection
'Definimos la colección
Set misCoches = New Collection
'Declaramos el contenedor de elementos de la colección
Dim elCoche As Variant
'Añadimos los elementos de la colección
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 colección
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 expresión sería equivalente a la anterior
'cocheBorrado = misCoches.Item(1)
8
Visítame en http://bit.ly/NckAccess
'----------------------------------------------
'Borramos el primer coche
misCoches.Remove (1)
MsgBox "¡Oh! No recordaba que el primer coche lo vendí
por un pastón" _
& vbCrLf & vbCrLf & "Ahora sólo tengo " &
misCoches.Count & " 'cochecitos'", _
vbExclamation, "#COCHES"
MsgBox "Quiero decir, que el coche que vendí fue el " &
cocheBorrado, vbInformation, "VENDIDO"
End Sub
…
Y sólo nos queda, en cualquier formulario, añadirle este código a un botón de comando:
…
Private Sub cmdLlamaColecCoches_Click()
Call colecCoches
End Sub
…
Si analizáis el primer código veréis cómo he manipulado la colección y sus propiedades según
lo que os he estado explicando en apartados anteriores. No creo que tenga mayor dificultad
para nuestros ya entrenados cerebros
Sólo quisiera llamaros la atención sobre algo que no habíamos comentado aún, y que es la
propiedad ITEM. Fijaos que cuando asigno valor a la variable <cocheBorrado> lo hago a través
de su clave, así:
cocheBorrado = misCoches("PorCar")
Pero si no tuviera clave, o mi “guía” fuese el índice del elemento en la colección, podría utilizar
esta otra expresión:
cocheBorrado = misCoches.Item(1)
CLASES
Nuestro amigo Access nos define una clase como <<Definición formal de un objeto. La clase
actúa como plantilla desde la que se crea una instancia de un objeto en tiempo de ejecución.
La clase define las propiedades del objeto y los métodos utilizados para controlar su
comportamiento>>.
Veamos:
• Define un objeto. Eso significaría que lo que nos permite crear son objetos, y en los
capítulos anteriores hemos visto algunas de las muchas cosas que se pueden hacer con
los objetos.
• Actúa 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
Visítame en http://bit.ly/NckAccess
Quizá lo anterior pueda resultar un poco confuso, pero un
ejemplo gráfico creo que nos ayudará: supongamos que yo
creo una clase que se llama “rectángulo”. Cuando necesito
un objeto “rectángulo” 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 ejecución. Lo que significa, para
entendernos, que se crea “mientras tenemos Access en marcha”.
• La clase define las propiedades del objeto y los métodos utilizados para controlar su
comportamiento. Ya sabemos pues que el objeto tendrá propiedades y métodos, y que
podremos establecer sus valores para que la instancia se comporte según nuestros
deseos.
Aunque no hayamos sido conscientes con los ejemplos que hemos ido aprendiendo durante
este curso estábamos realizando este proceso. Por poner un ejemplo “fresco”, ¿recordamos el
capítulo dedicado al “Scripting Runtime”, en concreto el ejemplo de nuestro “diccionario”
(capítulo 17)?
…
'Declaramos las variables
Dim abv As Object
'Creamos el objeto abv
Set abv = CreateObject("Scripting.Dictionary")
'Añadimos los significados de las abreviaturas
abv.Add "DDCG", "Dar de comer al gato"
…
fncMiTip = abv.Item(vAbreviado)
…
10
Visítame en http://bit.ly/NckAccess
instancia del objeto de la clase Scripting.Dictionary. La
estábamos creando, evidentemente, en tiempo de ejecución
(no “parábamos” Access para poder crear dicho objeto) y, a
continuación, manipulábamos, en este caso, un método de
la clase, que era ADD, y una propiedad, en este caso, ITEM.
Voy a explicar el proceso relacionándolo con los puntos anteriores, para que podáis seguir
mejor el hilo de la explicación.
Para cumplir el punto nos vamos al editor de VB y en el menú Insertar añadimos un módulo
de clase. Lo guardamos como clsVehic.
Para cumplir los puntos y vamos a definir las características que necesitaremos. Para ello
escribimos en nuestro módulo de clase lo siguiente:
…
Option Compare Database
Option Explicit
Para cumplir con el punto vamos a necesitar unas funciones que nos calcularan los
resultados. La primera función nos unirá el nombre con su tipo; la segunda función nos
calculará cuánto costaría llenar el depósito 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).
…
Public Function nomVehic() As String
nomVehic = nombre & " " & tipo
End Function
11
Visítame en http://bit.ly/NckAccess
If costeDeposito > 150 Then
MsgBox "¡Qué caro! Mejor dejar el vehículo
aparcado!", vbExclamation, "UFFF"
End If
End Function
…
Ya tenemos pues nuestro módulo de clase creado con todas las características que
necesitábamos. Ese módulo de clase lo podríamos exportar para poder utilizarlo en diferentes
bases de datos que tuviéramos sobre vehículos.
Se nos abrirá una ventana que nos pedirá dónde queremos guardarlo. Como es un módulo de
clase tendrá la extensión cls.
12
Visítame en http://bit.ly/NckAccess
Si quisiéramos realizar una importación de clase el proceso sería el mismo (situándonos en
cualquier espacio en blanco en la ventana de proyecto): haríamos click derecho y elegiríamos
la opción “Importar archivo...”
…
Private Sub cmdListaVehiculos_Click()
Call misVehiculos
End Sub
…
…
Public Sub misVehiculos()
'Definimos la colección
Set colMisVehic = New Collection
'Declaramos un objeto perteneciente a nuestra clase
Dim unVehiculo As clsVehic
'Declaramos una variable que recogerá los elementos de la colección, y
'que también 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 características técnicas de los vehículos 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 toméis estos valores como referencias
reales.
13
Visítame en http://bit.ly/NckAccess
.cilindrada = 3000
.capacDep = 80.5
End With
'Lo añadimos a nuestra colección
colMisVehic.Add unVehiculo, "PorCar"
'Rellenamos el siguiente vehículo
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 vehículo
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 vehículo
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 vehículo
Set unVehiculo = New clsVehic
With unVehiculo
.claseVehic = "Camión"
.nombre = "Mercedes"
.tipo = "Pegaso"
.cilindrada = 4000
.capacDep = 120.7
End With
colMisVehic.Add unVehiculo, "MerPeg"
'Ya podemos mostrar la información de la colección a petición del usuario
'No comento esta parte de código porque deberíamos entenderla ya perfectamente
Dim vClaseVehic As Variant
Dim vPrecioCombustible As Variant
Peticion:
vClaseVehic = InputBox("Seleccione qué información desea: 1-Coches; 2-Motos;" _
& " 3-Camiones; 0-Todos", "INFORMACIÓN VEHÍCULOS", 0)
If StrPtr(vClaseVehic) = 0 Then GoTo BorraColeccion
If Not IsNumeric(vClaseVehic) Then
MsgBox "El valor introducido no es válido", vbCritical, "INCORRECTO"
GoTo Peticion
End If
If vClaseVehic < 0 Or vClaseVehic > 3 Then
MsgBox "El valor introducido no es válido", 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")
'También, por simplificar, no introduzco elementos de control para el valor introducido
'Si quisiérais utilizarlos os podéis 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 vehículo tiene las siguientes características:" & vbCrLf & vbCrLf _
14
Visítame en http://bit.ly/NckAccess
& "Clase: " & elemVehic.claseVehic & vbCrLf _
& "Nombre: " & elemVehic.nomVehic & vbCrLf _
& "Cilindrada: " & elemVehic.cilindrada & vbCrLf _
& "Capacidad del depósito: " & elemVehic.capacDep & vbCrLf _
& "Precio de llenado del depósito: " & elemVehic.costeDeposito(vPrecioCombustible), _
vbInformation, "DATOS"
Next elemVehic
Case 1
For Each elemVehic In colMisVehic
If elemVehic.claseVehic = "Coche" Then
MsgBox "El vehículo tiene las siguientes características:" & vbCrLf & vbCrLf _
& "Clase: " & elemVehic.claseVehic & vbCrLf _
& "Nombre: " & elemVehic.nomVehic & vbCrLf _
& "Cilindrada: " & elemVehic.cilindrada & vbCrLf _
& "Capacidad del depósito: " & elemVehic.capacDep & vbCrLf _
& "Precio de llenado del depósito: " & elemVehic.costeDeposito(vPrecioCombustible), _
vbInformation, "DATOS"
End If
Next elemVehic
Case 2
For Each elemVehic In colMisVehic
If elemVehic.claseVehic = "Moto" Then
MsgBox "El vehículo tiene las siguientes características:" & vbCrLf & vbCrLf _
& "Clase: " & elemVehic.claseVehic & vbCrLf _
& "Nombre: " & elemVehic.nomVehic & vbCrLf _
& "Cilindrada: " & elemVehic.cilindrada & vbCrLf _
& "Capacidad del depósito: " & elemVehic.capacDep & vbCrLf _
& "Precio de llenado del depósito: " & elemVehic.costeDeposito(vPrecioCombustible), _
vbInformation, "DATOS"
End If
Next elemVehic
Case 3
For Each elemVehic In colMisVehic
If elemVehic.claseVehic = "Camión" Then
MsgBox "El vehículo tiene las siguientes características:" & vbCrLf & vbCrLf _
& "Clase: " & elemVehic.claseVehic & vbCrLf _
& "Nombre: " & elemVehic.nomVehic & vbCrLf _
& "Cilindrada: " & elemVehic.cilindrada & vbCrLf _
& "Capacidad del depósito: " & elemVehic.capacDep & vbCrLf _
& "Precio de llenado del depósito: " & elemVehic.costeDeposito(vPrecioCombustible), _
vbInformation, "DATOS"
End If
Next elemVehic
End Select
'Borramos los elementos de la colección
BorraColeccion:
Dim i As Long
For i = colMisVehic.Count To 1 Step -1 'Realizamos una cuenta atrás
colMisVehic.Remove (i)
Next i
End Sub
…
1.- Definimos las colecciones y los objetos, y los relacionamos, mediante dicha definición, con
el módulo de clase que hemos creado.
2.- Rellenamos los datos del elementos y lo añadimos a la colección.
3.- Repetimos el proceso de rellenado con todos los elementos que queramos.
4.- Solicitamos la información al usuario
5.- En función de lo que quiere ver el usuario (coche, moto o camión), para lo cual utilizamos
un SELECT CASE...END SELECT, recorremos los elementos de la colección a través 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 métodos (es decir, con las dos funciones que habíamos
definido en el módulo de clase). En este caso la operación es mostrar un MsgBox con la
información pertinente.
15
Visítame en http://bit.ly/NckAccess
7.- Finalizado el proceso, borramos todos los elementos de la colección para dejarla vacía.
La pregunta que nos podría dar origen a esta explicación es: ¿qué pasa si el valor asignado a
capacidad del depósito de combustible no es correcta? Es decir, que, por error, introducimos
una capacidad de 10000 litros (que yo sepa, no hay ningún vehículo, dentro de los tipos de
vehículos sobre los que estamos trabajando, que pueda tener un depósito así: ¡habría más
depósito que vehículo!).
También nos permite que una propiedad de una clase adopte un comportamiento determinado
en función de los parámetros que reciba.
PROPERTY LET
Mediante la instrucción PROPERTY LET generamos el código encargado de gestionar las
características de la propiedad del elemento definido en la clase.
…
Public Property Let …
'Si pasa esto haz esto
'Si pasa aquello haz esto otro
'Si pasa eso haz eso otro
End Property
…
PROPERTY GET
Para poder obtener el valor asignado a la propiedad utilizaremos la instrucción PROPERTY GET.
16
Visítame en http://bit.ly/NckAccess
Hablando en abstracto, podríamos comparar un PROPERTY GET con una función, dado que
devuelve un valor.
Su estructura sería:
…
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.
…
Public Property Set nombre(variableX As Objeto)
Set variableY = variableX
End Property
…
Manos a la obra...
Vamos a suponer que no hay vehículo (de los nuestros) que pueda tener un depósito superior
a los 500 litros. Aprovecharemos para comprobar también que no se nos haya “colado” un
depósito con capacidad negativa. El resto de elementos del código serán los mismos.
En ese nuevo módulo de clase escribimos el siguiente código (ojo, marco en negrita lo nuevo;
el resto es como ya lo habíamos escrito en el ejemplo del apartado anterior):
…
Option Compare Database
Option Explicit
17
Visítame en http://bit.ly/NckAccess
Select Case capacidad
'Si la capacidad es superior a 500 litros
Case Is > capacidadMax
Err.Raise 666, "clsVehic2", "La capacidad del depósito de
combustible no es real"
'Si la capacidad es negativa
Case Is < 0
Err.Raise 667, "clsVehic2", "La capacidad del depósito no
puede ser menor que cero"
Case Else
'Si no el valor es considerado correcto
p_capacDep = capacidad
End Select
End Property
• La variable que nos hace de “puente” entre Property Let y Property Get la hemos
llamado p_capacDep, pero, atención, la hemos definido como Private, para que su
ámbito de actuación sea sólo a nivel de clase (es decir, que no es accesible desde otros
módulos).
Sigamos: debemos crearnos un nuevo módulo estándar para generar la colección que nos dará
la información de nuestros vehículos. A este nuevo módulo lo llamaremos mdlVehic2. Para
simplificar sólo rellenaremos un vehículo por tipo y los listaremos, sin pedir otra cosa al
4 Para “refrescar memorias” podéis consultar el capítulo 13 de este curso
18
Visítame en http://bit.ly/NckAccess
usuario que el precio del combustible.
…
Option Compare Database
Option Explicit
19
Visítame en http://bit.ly/NckAccess
BorraColeccion:
Dim i As Long
For i = colMisVehic.Count To 1 Step -1 'Realizamos una cuenta atrás
colMisVehic.Remove (i)
Next i
End Sub
…
…
Private Sub cmdListaVehicProperty_Click()
Call misVehiculos2
End Sub
…
Si hacemos click sobre ese botón (con el formulario en vista formulario) se nos solicitará el
precio del litro de combustible y nos enumerará, a través de MsgBox, nuestros vehículos con
sus características.
Si ahora modificamos la capacidad del depósito 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
…
…
.capacDep = -80.5
…
20
Visítame en http://bit.ly/NckAccess
UNAS BREVES EXPLICACIONES TEÓRICAS BASADAS EN TODO LO
ANTERIOR
Para profundizar en el marco teórico en base al ejemplo anterior vamos a ponernos metafísicos
y vamos a hablar del alma y del cuerpo. Me vais a permitir esta pequeña licencia porque me
viene “que ni pintada” para que podamos entender lo que os quiero transmitir. Además, ¿quién
os iba a decir que la religión serviría para explicar VBA?5
Supongamos que existe una “esencia universal” (llamémosle Dios, el Uno, el Todo...), y
supongamos que una persona humana, al nacer, está compuesto por un cuerpo físico 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 sería 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 físico” de <miVehiculo> es diferente y diferenciable de <tuVehiculo>,
pero sus almas, aunque diferentes, son partes de una “esencia universal” (= clase).
Bajemos un nivel: mi código VB y yo tomamos una gran decisión: vamos a tener un hijo. A
este hijo le vamos a poner de nombre <elHijoVehículo>.
La pregunta que nos hacemos en este punto es: ¿existe <elHijoVehículo>? Y la respuesta es:
sí existe “a nivel mental”, porque mi código y yo así lo hemos decidido, pero aún no existe a
nivel físico porque aún no ha sido concebido.
Y por fin vamos a poner sobre la mesa y en conjunción todo este planteamiento con lo que
acabamos de programar en el ejemplo anterior:
1.- Creamos la “esencia universal” → Eso se refleja en la creación de la clase (creación del
módulo de clase).
5 Os ruego que toméis esta explicación únicamente como lo que es: una explicación. En ningún momento pretendo entrar en
valoraciones, ni críticas, 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 más claro posible en la explicación.
21
Visítame en http://bit.ly/NckAccess
3.- Concebimos <elHijoVehículo> → Eso se produce cuando hacemos
With elHijoVehiculo
.Pelo = “Pelón”
.Nariz = “Como la del padre”
.Peso = “3 Kg”
.Lloro = “Muy llorón”
End With
En definitiva, que a través de todo lo anterior ya deberíamos tener muy claro todo el proceso
y, si nos falla algo, tendremos una “guía de pasos” para “detectar” en qué fase podría estar el
error.
…
'Rellenamos el siguiente vehículo
Set unVehiculo = New clsVehic
With unVehiculo
…
Imaginemos que yo tengo una clase, clsBebe, y defino un ejemplar de clase así:
With miBebe
.Caracter = “Dulce”
.Ojos = “Llorones”
End with
Caso A: rellenando directamente las propiedades (sin el Set miBebe = New clsBebe)
With miBebe
22
Visítame en http://bit.ly/NckAccess
.Caracter = “Gruñón”
.Ojos = “Desafiantes”
End with
Caso A → NO hemos obtenido otro bebé, sino que lo que hemos hecho es mostrar mi bebé en
su adolescencia
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 teníamos un bebé; a continuación 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 código anterior (en el procedimiento “Public
Sub misVehiculos”) convirtáis en comentarios todos los <Set unVehiculo = New clsVehic>,
exceptuando el primero, y ejecutéis el código. Así podréis ver qué grata sorpresa nos llevamos.
Dado que quizá ya entremos en terrenos algo complejos os recomiendo que no sólo analicéis
los códigos que vendrán, sino también cómo se realiza el planteamiento del problema. Ni que
decir tiene que si el código es técnicamente perfecto pero el problema no está bien planteado y
planificado los resultados no van a ser satisfactorios.
He aquí el problema:
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 características que
23
Visítame en http://bit.ly/NckAccess
necesitamos. A esa tabla la llamaremos TAutos. Tendrá la siguiente estructura (algunos
campos se podrían haber desglosado en dos o más, pero los he unificado a efectos de
simplificar al máximo y no hacer el ejemplo engorroso en demasía):
Fijaos que para los campos [GamaAuto], [TerrenoAuto] y [TipoCombAuto] lo ideal hubiera sido
crearnos tablas auxiliares con la información, y que nuestra TAuto hubiera “chupado” los datos
de dichas tablas auxiliares. Sin embargo, a efectos de simplificación, nosotros escribiremos los
valores directamente.
Hagamos notar que el consumo medio se refiere al consumo en litros cada 100 kilómetros (por
si no quedaba claro qué significaba ese valor).
6 Los datos que veréis son totalmente inventados. No toméis estos datos como datos “de la vida real”.
24
Visítame en http://bit.ly/NckAccess
• El precio del alquiler irá en función de la gama del vehículo y de los días de alquiler.
Nuestro cliente nos indicará cuántos días va a necesitar el vehículo → Requeriremos de
una tabla auxiliar que nos dé los precios por día, según la gama, y que un trabajador
nuestro actualizará tan pronto como la empresa decida modificar esos
precios.
25
Visítame en http://bit.ly/NckAccess
Espero que, hasta aquí, no nos hayamos perdido... je, je...
Veréis que he programado un procedimiento PROPERTY para comprobar que no pueda haber
un consumo medio negativo o igual a cero.
Eso lo podría haber controlado a través del campo [ConsumMedioAuto] de la tabla TAutos, con
una regla de validación, pero como la idea es practicar las clases lo controlaremos desde aquí.
…
Option Compare Database
Option Explicit
Como vemos, nuestra clase recogerá toda la información que queremos proporcionar al cliente.
26
Visítame en http://bit.ly/NckAccess
Para clarificar ideas digamos que:
Siguiente fase: creemos un módulo estándar. A ese módulo estandar lo llamaremos mdlAuto.
¿Qué va a hacer ese módulo? Lo que va a hacer es un doble proceso, adornado con algunas
operaciones adicionales:
Uno: va a recoger toda la información 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 según
las necesidades del cliente y a través de la cual podremos preparar un informe para
entregárselo a nuestro seguro consumidor.
…
Option Compare Database
Option Explicit
'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 código
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 través de una SQL. La escribo estructurada
'en líneas para que apreciemos perfectamente los campos que se crearán
'Para relacionarlo con el código posterior, tened en cuenta que:
27
Visítame en http://bit.ly/NckAccess
'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 través de la ejecución de la SQL
dbs.Execute miSql
Fijaos en cómo 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
Visítame en http://bit.ly/NckAccess
para servir.
...
'Relleno los datos 'fijos' con la información del registro
...
para dichos datos 'fijos', y con los datos variables hemos necesitado, simplemente recuperar el
valor de los argumentos a través de las variables buscoXXX y pasárselos al método, a través
de las líneas
…
'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)
…
También fijaos en que los datos “externos”, que deben ser proporcionados por nuestro cliente
(previsión de kilómetros a recorrer y días que quiere alquilar el vehículo) y que, lógicamente,
no sabemos a priori, los paso como argumentos del procedimiento, a través 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 módulo de trabajo mdlAuto, un procedimiento que
eliminaremos tras su ejecución (o, si no queremos eliminarlo, podemos convertir en
comentario), y que será el mismo del código anterior con unas ligerísimas modificaciones
(prácticamente es un copy-paste de un fragmento del código anterior; os marco en negrita lo
que se debe cambiar, que está hacia el final del código):
29
Visítame en http://bit.ly/NckAccess
Private Sub creoTablaPorPrimeraVez()
'Creamos la estructura de la tabla a través 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 través de la ejecución de la SQL
CurrentDb.Execute miSql
End Sub
…
Nos situamos sobre ese Sub y pulsamos F5. Nuestra tabla se creará. Ya podemos borrar el
código, o convertirlo en comentario. Tened en cuenta que:
Y ya llegamos a la fase en el que el usuario tendrá una participación activa. Vamos a crearnos
un formulario en blanco que llamaremos FInfoCliente. Yo lo crearé con TextBox para simplificar,
pero lógicamente ya sabríamos crear otros controles, como cuadros combinados o cuadros de
lista, para hacerlo más atractivo y eficiente de cara al usuario. Lo que haremos será lo
siguiente:
30
Visítame en http://bit.ly/NckAccess
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
…
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, asignándole los parámetros requeridos
Call creoTAux(vKm, vDias)
'Creo el filtro para abrir el informe
filtroDeseosCliente = "[Gama]='" & vGama & "' AND [Terreno]='" & vTerreno & "'"
'Abro el informe, filtrándolo por las peticiones del cliente
DoCmd.OpenReport "RAuxInfoCliente", acViewPreview, , filtroDeseosCliente
End Sub
…
Y creo que ya está. Esta vez no diré aquello de... ¿fácil, verdad?
Alguien me podría objetar: “para desarrollar este último ejemplo se podrían haber utilizado
otros métodos, y quizá no tan complicados”, y yo diré: “Totalmente de acuerdo... si sólo nos
centramos en el ejemplo”. Pero la “gracia” de lo anterior es que nuestra futura aplicación no es
sólo darle la información que hemos comentado al cliente, sino que, hipotéticamente, la BD
nos serviría para gestionar nuestro negocio. Y la pregunta es: “Si, por ejemplo, tenemos que
emitir una factura al cliente, ¿deberíamos volver a calcular todo de nuevo mediante código? O,
si por ejemplo, un histórico nos muestra una media de días que se alquila un coche de una
determinada gama, y una media de kilómetros que realiza dicho automóvil, y queremos sacar
una previsión de cara al año siguiente, ¿debemos volver a realizar por tercera vez todos los
cálculos? ¿No es mejor tener los cálculos y datos “clave” recogidos en nuestra clase, y acceder
a ella cuando los necesitemos? Porque así sólo necesitamos programar dichos cálculos una sola
vez, ¿no es cierto?”
En fin... que creo que, según cómo sea nuestro proyecto, la utilización de clases es un recurso
31
Visítame en http://bit.ly/NckAccess
muy útil... y ahora ya sabemos cómo manejarlo.
Espero que lo que hayáis podido aprender de este capítulo os sea útil.
Un saludo y...
¡suerte!
32
Visítame en http://bit.ly/NckAccess