jueves, 4 de septiembre de 2014

VBA: Cómo crear un tipo de dato definido por el usuario.

Aprenderemos a crear nuestros propios tipos de datos, que podremos usar como variables en nuestros procedimientos.
Comenzaremos repasando brevemente cuáles son los tipos de datos estándar en VBA (más habituales!):
Tipo Dato: Boolean
Memoria: En función de la plataforma de implementación
Valores: True o False

Tipo Dato: Date
Memoria: 8 bytes
Valores: 0:00:00 (medianoche) del 1 de enero de 0001 a 11:59:59 p.m. del 31 de diciembre de 9999.

Tipo Dato: Integer
Memoria: 4 bytes
Valores: -2.147.483.648 a 2.147.483.647 (con signo)

Tipo Dato: Long (entero largo)
Memoria: 8 bytes
Valores: -9.223.372.036.854.775.808 a 9.223.372.036.854.775.807 (9,2...E+18 †) (con signo)

Tipo Dato: String (longitud variable)
Memoria: En función de la plataforma de implementación
Valores: 0 a 2.000 millones de caracteres Unicode aprox.

Tipo Dato: Double (punto flotante de precisión doble)
Memoria: 8 bytes
Valores: -1,79769313486231570E+308 a -4,94065645841246544E-324 † para los valores negativos; 4,94065645841246544E-324 a 1,79769313486231570E+308 † para los valores positivos

y otros como: Byte, Decimal, Double (punto flotante de precisión doble), Object, Variant, Currency...

Pero hoy nos interesan en especial:
Tipo Dato: User-Defined(estructura)
Memoria: En función de la plataforma de implementación
Valores: Cada miembro de la estructura tiene un intervalo de valores determinado por su tipo de datos y es independiente de los intervalos de valores correspondientes a los demás miembros.


Remarcar lo fundamental de definir el tipo de datos de nuestras variables, y que hacerlo mal puede suponer un error en nuestros procedimientos.

Centrándonos en el asunto que nos ocupa, debemos saber que cualquier tipo de datos se define mediante la instrucción Type, y que los Tipos de datos definidos por el usuario podrán contener uno o más elementos de un tipo de datos, una matriz o incluso otro tipo de dato definido por el usuario previamente.
Diría que el uso de Tipo de datos definidos por el usuario son especialmente útiles cuando tenemos que pasar información entre diferentes procedimientos. En lugar de tener, digamos, cuatro parámetros en un mismo procedimiento, podríamos emplear un Tipo de datos definido por nosotros, con cuatro elementos.
Recomendable para hacer nuestro código más legible y mejor documentado.


Comencemos entonces poniendo los antecedentes del ejemplo a explicar.
Supongamos que trabajamos con un registro de Ventas de nuestros comerciales, con información del Comercial, Zona de trabajo, su Antigüedad en la empresa y el número de Ventas. En este caso, es posible que tengamos que trabajar con los valores de los diferentes valores de cada Comercial.
Una forma de hacer esto sería configurar las variables para cada elemento de los datos:

Dim Comercial As String
Dim Zona As String
Dim Antig As Integer
Dim Ventas As Currency


Por supuesto esta forma de trabajar funciona, pero ¿y si necesitamos trabajar con los datos de varios Comerciales a la vez?... en este caso podríamos crear una nueva variable para cada Comercial, pero claro, esto parece demasiado ineficiente.

La mejor mejor manera, entonces, es crear un Tipo de dato compuesto de cuatro elementos (Nombre, Zona, Antigüedad, Ventas) que contenga toda la información requerida:

Type TipoDatoPropio
    comercial As String
    zona As String
    antig As Integer
    ventas As Currency
End Type


OJO, debemos incluirlo dentro de nuestro proyecto VBA en un módulo, fuera de nuestros procedimientos!!

Ya tenemos creado nuestro propio tipo de datos. Ahora podremos usarlo en nuestros procedimentos.

Estos son los datos en nuestra hoja de cálculo:

VBA: Cómo crear un tipo de dato definido por el usuario.



En un módulo del proyecto VBA incluimos el siguiente procedimiento, que carga de nuestra hoja de datos los valores para cada comercial:

Public Sub ProbandoTipoDatoPropio()
'comienzo definiendo una Matriz con un tipo de datos 'TipoDatoPropio'
Dim MiMatriz(8) As TipoDatoPropio
Dim i As Integer, x As Integer

'asignamos valores a nuestra matriz
For x = 0 To 7
    MiMatriz(x).comercial = Cells(x + 2, 1).Value
    MiMatriz(x).zona = Cells(x + 2, 2).Value
    MiMatriz(x).antig = Cells(x + 2, 3).Value
    MiMatriz(x).ventas = Cells(x + 2, 4).Value
Next x

'mostramos el resultado, recorriendo la matriz-Array creada...
For i = LBound(MiMatriz) To UBound(MiMatriz) - 1
    Debug.Print "Dato: " & MiMatriz(i).comercial & " " & MiMatriz(i).zona & " " & _
        MiMatriz(i).antig & " " & MiMatriz(i).ventas
Next
End Sub



Tras ejecutar el procedimiento veremos en nuestra ventana de inmediato:



Observemos de qué forma tan sencilla hemos cargado los datos de una matriz con varias columnas, y de qué forma podemos recuperar los valores.. incluso de manera segmentada por columnas/campos si así quisiéramos...

Otro ejemplo más sencillo:

Type diario
    NumReg As Integer
    Descripcion As String
    Debe As Currency
    Haber As Currency
    Saldo As Currency
End Type
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Sub PruebaTipoDatosdiario()
Dim regdiario As diario

'aisgnamos valores a nuestra variable
regdiario.NumReg = 1001
regdiario.Descripcion = "Suministros"
regdiario.Debe = 750
regdiario.Haber = 125
regdiario.Saldo = regdiario.Debe - regdiario.Haber

'mostramos un dato...
MsgBox regdiario.Saldo

End Sub

3 comentarios:

  1. Hola,

    En el caso de querer definir MiMatriz con 8 elementos quisieras definirla con un tamaño de una variable pasada por argumento, ¿cómo lo harías? Me da un error de que sólo se puede definir con una constante

    Algo así:
    Public Sub ProbandoTipoDatoPropio(ByVal tam As Integer)
    ...
    Dim MiMatriz(tam) As TipoDatoPropio
    ...
    End Sub

    Muchas gracias

    ResponderEliminar
    Respuestas
    1. Hola David,
      fíjate en el primer código del post.
      Es un tema delicado este de ByVal o ByRef:
      http://excelforo.blogspot.com.es/2016/08/vba-cuando-y-como-pasar-argumentos-por.html
      Has probado ByRef ?

      Eliminar
  2. Muchas gracias por tu respuesta.

    He probado con ByRef aunque ya me daba que no iba a funcionar porque el error que da al compilar el código es que tengo que utilizar una constante.

    Simplemente, creo que vba no permite esta acción de ninguna manera.

    Saludos.

    ResponderEliminar