Esta es la segunda parte de los posts para enseñar a usar macros de Excel. Si te perdiste la primera parte, aquí la puedes encontrar. En esta segunda lección nos familiarizaremos con el editor de código y aprenderemos a trabajar con variables y algunas estructuras de datos.
Trata de ir despacio, un poco cada día, comprendiendo bien y luego prosiguiendo. No vayas con prisa porque voy a presentar bastante información, y lo más importante es que te familiarices poco a poco.
El editor de código de VBA
El área de trabajo del editor se divide en 4 zonas:
- Módulos
- Propiedades
- Código o form
- Pantalla de mensajes de depuración
Módulos
Los módulos son como una especie de pergamino largo donde escribes código. Cada uno de los "pergaminos" de las hojas de cálculo abiertas se muestran en esta zona. Los módulos pueden tener asociada una interface gráfica (una ventana de Windows) asociada, o pueden no tenerla y ejecutar instrucciones sin desplegar nada.
Hay 3 tipos de módulos:
- Forms: Código que tiene una ventana de Windows asociada.
- Modules: Código sin interface gráfica.
- Class modules: Código que se usa para crear objetos. Es para programadores más avanzados, no vamos a cubrir esta parte aquí.
Propiedades
Si seleccionas un módulo o un elemento de la interface gráfica de tu programa, verás que se tiene asociada una lista de valores asociados a características, llamadas propiedades, para cada uno.
Código o form
El código está compuesto por instrucciones que tu le das a la máquina. Esas instrucciones se ejecutan, pero no necesariamente resultan visibles al usuario durante la ejecución. En pocas palabras aquí es donde escribirás el código. Sólo asegúrate de que estás ubicado en el módulo apropiado.
Los forms (o formularios) son lo que tu llamarías una "ventana" que en realidad es una superficie que contiene controles, como por ejemplo un botón o una zona para escribir texto, y que se muestra visible en algún momento de la ejecución.
Pantalla de mensajes de depuración
Cuando estás haciendo tu programa, puedes desplegar lo que quieras en esta región, usando el comando DEBUG.PRINT seguido por lo que deseas que se despliegue. Es en realidad un área para el programador, porque el usuario de la macro no verá este texto a menos que entre al editor de macros durante una sesión. Normalmente un programador la usa para desplegar y verificar los datos o resultados que produce un programa en algún momento de la ejecución.
Editando forms
Cuando editas forms, vas a tener dos zonas de interés:
- Paleta de controles
- Form
En la paleta de controles escoges un control al pincharlo y vas al form a colocar el control. Los controles se colocan al dibujar un rectángulo encima del form, como cuando dibujas un rectángulo en MSPaint. Si haces doble clic sobre un control que colocaste sobre el form, pasarás a editar el código para dicho control.
Estructura del código dentro de los módulos
Cuando escribas código dentro del módulo incluirás procedimientos o subrutinas (Sub) y funciones (Function). Las subrutinas y funciones son fragmentos de código que tienen un propósito específico y que se activan en determinadas circunstancias, definidas por el que crea la macro. Cada subrutina o función tendrá un inicio y un final claramente definidos.
Antes de las subrutinas y funciones se efectúa la declaración de variables y estructuras de datos que vas a usar y que serán utilizadas por varias subrutinas y funciones del módulo.
Entendiendo las variables como medio para almacenar datos
Puedes imaginar las variables como celdas de datos que existen en memoria pero que no puedes ver, y al igual que en matemática, a dichas celdas se les asigna un nombre de una variable. Por ejemplo, en lugar de decir que la celda A2 contiene un número 3, podríamos decir que la variable X contiene un número 3. La variable X es como una celda oculta que no ves y que contiene el número. Esas variables necesitan ser creadas en la memoria, algo a lo que se le llama "dimensionar" o "declarar" una variable.
Para declarar o crear una variable X debemos indicar el tipo de variable que queremos, dependiendo del tipo de dato que almacenaremos. En este caso crearemos una variable X del tipo Long (sólo admite números enteros). El tipo indica el tipo de datos que va almacenado en la variable.
Dim X As Long
Aunque existen muchos tipos de datos, sólo voy a enumerar los tipos de datos más comunes que deberías usar:
- String: Representa variables que contienen texto (en realidad contienen un grupo de caracteres alfanuméricos y simbólicos).
- Long: Adminten valores enteros solamente
- Double: Admiten valores con punto decimal, ya sea valores muy grandes o valores con muchas cifras decimales.
- Date: Fechas. Este tipo de dato lo analizaremos más adelante.
- Variant: Este no es un tipo de datos que vayas a usar. Si se te olvida declarar una variable, no te dará un error, sino que VB lo asignará al tipo Variant y puede aceptar valores de cualquier tipo, pero a un costo. Procesar variables de tipo Variant hace muy lento lo que hagas. Evita la presencia de variables Variant o variables no declaradas.
En las subrutina o precedimiento ahora podemos usar esta variable X como la usaríamos en matemáticas. Cabe señalar que siempre es buena práctica inicializar la variable, darle un valor inicial. Imaginemos el siguiente código dentro de un módulo. Este código desplegará los valores de las variables en la pantalla de depuración, porque usa el comando Debug.Print.
En este ejemplo X tendrá un valor de 3 y la variable Y usará el valor de X al que le sumará 2. Se parece mucho a la manera de hacer fórmulas en secundaria. A la izquierda tienes la variable que almacenará el resultado y a la derecha una expresión de la cual resultará un valor que se almacena en la variable.
Dim X As Long
Dim Y As Long
Sub Main()
X = 3
Y = X + 2
Debug.Print "El valor de X es "; X ; " y el valor de Y es ";Y
End Sub
Cabe indicar que si declaras las variables al inicio, antes de la primera subrutina o función, los valores serán visibles por todas las subrutinas y funciones del módulo. Si colocas la declaración dentro de la subrutina, sólo será visible dentro de la subrutina.
Sub Main()
Dim X As Long
Dim Y As Long
X = 3
Y = X + 2
Debug.Print "El valor de X es "; X ; " y el valor de Y es ";Y
End Sub
Los vectores son como una colección de celdas que se llaman con un nombre de una variable, pero al contener varios valores deben ser direccionados por un subíndice.
He aquí un ejemplo que crea el vector y lo llena con valores, usando fórmulas. El asterisco (*) se usa para multiplicación y el slash (/) se usa para división.
Sub Main()
Dim A(4) As Long
A(0) = 100
A(1) = A(0) * 2
A(2) = A(0) + A(1) * 2
A(3) = 356
A(4) = 890 / 2
Debug.Print "El valor de A(0) es "; A(0)
Debug.Print "El valor de A(1) es "; A(1)
Debug.Print "El valor de A(2) es "; A(2)
Debug.Print "El valor de A(3) es "; A(3)
Debug.Print "El valor de A(4) es "; A(4)
End Sub
Cabe notar que en el código anterior el tamaño del vector es fijo. Tu puedes crear vectores de tamaño variable. En el siguiente ejemplo se crea el vector A, luego se le cambia el tamaño para que albergue el elemento cero, y luego se le cambia el tamaño para que albergue hasta el elemento 4. Este proceso de crear vectores sin un tamaño, y luego cambiarles el tamaño se conoce como "dynamic memory allocation" (asignación dinámica de memoria). La palabra Preserve indica que no debe borrar los valores ya existentes en el vector. Si no le pones esa palabra, cambiará el tamaño y vaciará el vector.
Sub Main()
Dim A() As Long
Redim A(0)
A(0) = 100
Redim Preserve A(4)
A(1) = A(0) * 2
A(2) = A(0) + A(1) * 2
A(3) = 356
A(4) = 890 / 2
Debug.Print "El valor de A(0) es "; A(0)
Debug.Print "El valor de A(1) es "; A(1)
Debug.Print "El valor de A(2) es "; A(2)
Debug.Print "El valor de A(3) es "; A(3)
Debug.Print "El valor de A(4) es "; A(4)
End Sub
Las matrices de dos dimensiones son como tablas. En este caso tenemos una matriz en dos dimensiones, pero podríamos tener una matriz de 3 dimensiones.
Asi podemos crear una matriz de la siguiente forma:
Dim A(3,3) As Long
A una matriz también le podemos aplicar el dynamic memory allocation, pero sólo para la última dimensión. Si declaraste una matriz de 3 x 5 (3 filas y 2 columnas) sólo podrás agregar columnas.
A la hora de usar los valores de la matriz, primero va el valor de la fila y luego el valor de la columna. En este ejemplo la fila 2 y columna 1 tendrá un valor de 6.
B(2,1) = 6
B(3,1) = B(2,1) + 2
En los casos anteriores tenemos una variable que representa un grupo de datos llamado Array (Arreglo). En los casos que vimos el tipo de dato que se usa es siempre el mismo para todos los elementos del arreglo. Sin embargo a veces podríamos tener estructuras de datos que no siempre contienen datos del mismo tipo.
Imagina que tenemos una tabla que contiene los siguientes datos de bolsa.
- Fecha y hora
- Precio de apertura
- Precio de cierre
- Precio máximo
- Precio mínimo
En lugar de crear 5 vectores, o crear 1 vector tipo Date para la fecha y una matriz de tipo Double para los precios, podemos crear una estructura que combina ambos.
Escribimos el siguiente código para declarar una estructura llamada TipoRegistro que es en realidad un tipo personalizado que combina varios tipos. La estructura estará fuera de las subrutinas y funciones, en la sección de declaración del módulo respectivo.
Private Type TipoRegistro
Fecha As Date
Apertura As Double
Cierre As Double
Maximo As Double
Minimo As Double
End Type
Y luego creamos una variable que contendrá esa estructura. La variable puede estar dentro o fuera de una subrutina o función.
Dim D(4) As TipoRegistro
Cuando queramos usar un valor de esa estructura, lo haremos de la siguiente manera. En este ejemplo Stop es otra variable que debería ser declarada en algún lado para que no sea de tipo Variant. Las variables no sólo pueden estar compuestas por una sola letra, sino que puedes darle un nombre a la variable (sin usar espacios) que signifique algo.
D(0).Apertura = 100
Stop = D(0).Apertura
Como notarás, D es un vector que en lugar de contener una fila de datos, contiene en realidad una fila de datos de un registro bursátil. Hasta ahora hemos aprendido a navegar en el editor, y hemos comprendido cómo crear espacios en memoria para extraer o almacenar datos, usando fórmulas.
Sin embargo las celdas de Excel también pueden usarse para almacenar valores o para extraer valores. En este ejemplo tomamos el valor de la celda E3 (fila 3, columna 5) y sumamos 1 y almacenamos el resultado en X. Asimismo la celda B1 (fila 1 y columna 2) almacenará el resultado de multiplicar Y por 5.
X = Cells(3,5) + 1
Cells(1,2) = Y * 5
Cabe añadir que aunque te parezca tentador usar celdas en lugar de variables, extraer o almacenar valores en celdas es un proceso muy lento, y por eso es mejor usar variables y minimizar el uso de celdas en fórmulas dentro de tu código. Lo mejor si vas a usar valores de celdas es pasar el valor de la celda a una variable y hacer operaciones con esa variable.
Repitiendo instrucciones usando FOR / NEXT
¿Podremos realizar cálculos más complejos que involucren procesos que se repiten muchas veces? Si. Seguramente recuerdas que en el código anterior teníamos este código:
Debug.Print "El valor de A(0) es "; A(0)
Debug.Print "El valor de A(1) es "; A(1)
Debug.Print "El valor de A(2) es "; A(2)
Debug.Print "El valor de A(3) es "; A(3)
Debug.Print "El valor de A(4) es "; A(4)
¿Qué pasaría si el vector que usamos tuviese 10 mil elementos en lugar de 5 elementos (desde 0 hasta 4)? Evidentemente deberías declarar el arreglo para que tenga 10 mil elementos.
Dim A(10000) As Long
Sería terriblemente cansado realizar el proceso de escribir 10 mil veces lo mismo. Lo mejor sería reemplazarlo por código que use For / Next:
For i = 0 to 10000
Debug.Print "El valor de A("; i ; ") es "; A(i)
Next i
En este caso la variable i (que deberías haber declarado también) sirve de contador, y su valor variará desde 0 hasta 10000. El código que se encuentra entre la línea donde stá el comando FOR y la línea donde está el NEXT, se repetirá y en cada iteración la variable i se incrementará de 1 en 1.
Cabe notar que si el FOR usa la variable "i", también el NEXT debe referirse a "i". Además, si haces el ciclo FOR NEXT desde 0 hasta 10 mil y el vector A tiene menos de 10 mil elementos, en algún momento lanzará un aviso de error, porque la variable "i" apunta a un valor del vector que no existe.
Prueba ahora este código en una macro hecha por tí:
Sub Main()
Dim fila as Long
Dim columna as Long
For columna = 1 to 4
For fila = 1 to 10
Cells(fila,columna) = columna * 10 + fila
Next fila
Next columna
End Sub
El resultado te parecerá muy interesante. Como observas aquí tenemos dod ciclos FOR, uno dentro del otro, que es lo que se llama tener "ciclos anidados". Cabe notar que el último FOR es el de la fila, y por ende el primer NEXT deberá ser para la fila.
Tomando decisiones con IF THEN ELSE
Vamos a llenar las primeras 10 filas de la primera columna en la hoja de Excel con valores numéricos. Si el valor de la primera columna es mayor que 5, entonces despliegue "SI" o de lo contrario despliegue "NO".
Sub Main()
Dim i As Long
Randomize Timer 'Activar generador de números aleatorios
For i = 1 to 10
Cells(i,1) = Int(Rnd * 10) 'Agregar un valor aleatorio entero de 0 a 10 en las celdas de la primera columna
If Cells(i,1)>5 Then 'Inicia toma de decisión. Si se cumple la condición de que el valor de la celda en la primera columna es mayor que 5 entonces...
Cells(i,2) = "SI" '...poner SI en la columna 2.
Else 'De otro modo, si no se cumple la condición...
Cells(i,2) = "NO" '...poner NO en la columna 2.
End If 'Aquí termina la decisión.
Next i
End Sub
Como puedes observar, lo que hizo el programa fue tomar una decisión. Rnd es un número aleatorio (en inglés se dice "random") cuyo valor oscila entre 0 y 1 pero nunca llega a ser 1. La función Int(x) lo que hace es tomar el valor x, para recortarle los decimales y obtener un número entero. Al multiplicar un número aleatorio entre 0 y 1 por 10, se obtiene un número aleatorio entre 0 y 10.
Prueba ejecutar este código varias veces.
Epílogo
Hasta ahora no hemos visto un ejemplo completo, sino que hemos experimentado un poco con código. Aprender a programar al inicio resulta un poco dificil porque uno requiere aprender muchas reglas, así que tómate tu tiempo para comprender cada ejemplo, lo que hace el código. Y si tienes preguntas las puedes postear aquí.
Creo que ya estamos listos para un ejemplo un poco más real para el siguiente post. Mientras llega, trata de familiarizarte y experimentar. Aquí se trata de hacer cosas a ver qué pasa, familiarizarse con una ambiente extraño. Todavía no vamos en serio.
Estoy consciente de que he ido un poco rápido y no he cubierto todo lo que tiene que ver con FOR/NEXT o IF/THEN/ELSE pero es que no he querido saturar de información.