Aula Macedonia


Curso de Programación en VBA para Excel


Artículo realizado por
Iñaki Ecenarro.





Capítulo 1. Introducción y primeros pasos

Este curso va dirigido a aprender a programar en Visual Basic for Applications (VBA) para la hoja de cálculo Microsoft Excel. El VBA es muy similar en el resto de herramientas de Microsoft Office (Word, PowerPoint, etc), por lo que los conocimientos aquí adquiridos pueden aplicarse en esos otros programas. Además el VBA es también muy similar al Visual Basic de verdad, por lo que puede ser una puerta de acceso a la programación de aplicaciones (utilizando Visual Basic) para personas sin conocimientos previos de programación.

Desde los primeros tiempos de las hojas de cálculo, con las míticas primeras versiones de Lotus 1-2-3, existían macros (el nombre completo era macro-comandos), que servían para automatizar tareas repetitivas. En aquellos tiempos las macros se limitaban básicamente a simular pulsaciones del teclado el usuario, es decir, al ejecutar una macro era como si el usuario estuviese pulsando las teclas que la macro "pulsaba", lo que a pesar de su sencillez permitía hacer cosas interesantes. Con el tiempo las macros fueron evolucionando, pudiéndose incluir en ellas sentencias que no se traducían en pulsaciones de teclas, aunque todo ello se hacía introduciendo fórmulas en las celdas de la hoja de cálculo, lo que dejaba bastante que desear. Con la llegada de Excel 5.0, Microsoft introdujo las macros basadas en el popular Visual Basic, creando lo que ha llamado Visual Basic for Applications, compartido por todas las aplicaciones de Microsoft, y que añade a las mismas unas posibilidades enormes de personalización y creación de soluciones a medida de las necesidades de cada usuario. De hecho, creo que el nombre "macro" debería dejar de utilizarse en favor de otros conceptos más relacionados con los lenguajes de programación (como rutinas, subrutinas y funciones), pero yo creo que se mantiene por razones históricas.

ClipoLo primero que tuve que decidir antes de escribir este curso sobre programación en Excel fue hacia quién iba a ir dirigido: por un lado están todas las personas que dominan uno o más lenguajes de programación, y con poco esfuerzo pueden aprender los detalles específicos de Visual Basic for Applications para Excel. Por otro lado están todas aquellas personas que utilizan Excel simplemente como una hoja de cálculo que hace operaciones aritméticas, que desaprovechan toda la potencia de Excel. He decidido que este curso va a ir dirigido a estos últimos, porque creo que es el perfil del usuario habitual de Excel, y aquellas personas que estén en el primer grupo pueden también utilizar el curso, deteniéndose en las partes que expliquen cosas específicas de Excel y saltándose otras como los conceptos generales de programación.

Una nota sobre versiones de Excel: la última versión de Excel es la de Office 97 (llamada Excel 97), aunque todavía existen muchos sitios en los que se utiliza la versión de Office 95 (Excel 95). Casi todo lo que vamos a hacer funciona en las dos versiones, y en los casos en los que no sea así procuraré indicarlo.

El mejor método para aprender VBA es utilizar la opción de grabar macros de Excel: todo lo que hagamos mientras Excel está grabando una macro se traduce en la instrucciones de VBA necesarias para repetir nuestras acciones. Vamos a utilizar esa opción para crear nuestra primera macro. Primero selecciona la opción "Herramientas, Grabar Macro", y escribe algo en la celda A1. Luego selecciona la opción "Herramientas, Grabar macro..., Detener grabación" para que Excel debe de grabar. Para ver la macro que acabamos de crear el método es distinto en Excel 95 y Excel 97: en Excel 95, las macros se almacenan en módulos, que son como una hoja más del libro, podemos ver una hoja llamada "Módulo1" en las pestañas que están en la parte inferior. En Excel 97, para escribir macros se utiliza el Visual Basic Editor, y accedemos a él mediante la opción Herramientas, Macros, Abrir Editor Visual Basic. En cualquiera de las dos versiones veremos que Excel ha escrito algo parecido a esto:


Sub Macro1()
    ActiveCell.Formula = "Mi primera macro"
    Range("A2").Select
End Sub

Esta rutina escribe "Mi primera macro" en la celda activa y luego se desplaza a la celda inferior, en este caso la celda A2 (esto ocurre porque Excel tiene por defecto la opción de que cuando pulsas "Intro" el cursor se desplaza a la celda de abajo, y Excel también ha incluido eso en la macro).

Vamos a ir poco a poco. La primera línea define una subrutina llamada Macro1 (es el nombre que le ha puesto Excel, pero podemos cambiarlo a lo que nosotros queramos). Cada rutina que escribamos debe empezar con Sub y terminar con una sentencia "End Sub".

Antes de explicar la segunda línea, una explicación sobre los "objetos": un objeto es una variable de VBA que representa cualquier elemento de Excel. Por ejemplo, para representar un rango de una hoja de cálculo se utiliza el objeto Range, o para representar una hoja de cálculo se utiliza el objeto Worksheet. En nuestra macro estamos utilizando el objeto "ActiveCell", que es un objeto de tipo Range que siempre apunta a la celda activa.

Los objetos tienen "propiedades" y "métodos". Una propiedad es un atributo del objeto que define una característica del mismo. Por ejemplo, la propiedad "Row" del objeto "ActiveCell" nos indica en qué fila de la hoja de cálculo está la celda activa. Para acceder a una propiedad de un objeto se utiliza el nombre del objeto, un punto y el nombre de la propiedad (p.ej. ActiveCell.Row). Unas propiedades muy utilizadas son las propiedades "Value" y "Formula" que se aplican a todos los objetos Range. En nuestro ejemplo de macro, asignamos a la propiedad "Formula" del objeto ActiveCell un texto, que es como si el usuario escribiera ese texto en esa celda.

Los "métodos" son acciones que se pueden llevar a cabo sobre un objeto, son rutinas que se aplican sobre el objeto. Para llamar a un método se utiliza el nombre del objeto, un punto y el nombre del método. Por ejemplo, el método "ActiveCell.ClearContents" borra el contenido de la celda activa (es decir, como si el usuario pulsa la tecla "Suprimir").

Volvamos a nuestra primera macro. La segunda línea asigna un valor a la propiedad "Formula" del objeto ActiveCell. En realidad no es una formula sino una cadena, pero da lo mismo. Fíjate en que en VBA siempre que escribamos una cadena de carácteres hay que encerrarla entre comillas dobles ("), igual que en otros lenguajes. Si dentro de una cadena queremos poner unas comillas dobles, sólo tenemos que escribirlas dos veces ("en esta cadena hay unas comillas "" dobles")

La tercera línea llama al método Select del rango "A2" de la hoja activa. Fíjate en la forma de obtener el objeto que representa a la celda "A2", utilizando Range("A2"). La última línea se encarga de indicar dónde termina la rutina. Por cada Sub que escribamos obligatoriamente tenemos que escribir un "End Sub".

Ejecutar una subrutina

Para ejecutar una rutina hay varios métodos.

Podemos utilizar cualquiera de estos métodos (y otros que ya veremos) para ejecutar nuestra rutina, y comprobaremos que cada vez que la ejecutamos escribe un texto en la celda activa y luego desplaza la selección a la celda de abajo.

Utilizar funciones de VBA

Además de los objetos con sus métodos y propiedades Excel también tiene funciones. Para llamar a una función simplemente hay que escribir su nombre y luego los parámetros necesarios. Por ejemplo, vamos a hacer una pequeña macro que utilice la función MsgBox. Esta función sirve para presentar cuadros de diálogo con mensajes para el usuario, aunque no tenemos muchas opciones para diseñar el diálogo, sólo se puede elegir el tipo de icono entre varios predefinidos (interrogación, exclamación, etc.) y unas cuantas opciones sobre los botones del cuadro de diálogo (Aceptar, Cancelar, Sí, No...). A pesar de todo es muy útil para presentar información al usuario, por ejemplo cuando se ha terminado un proceso con éxito, cuando ha ocurrido un error, o para pedir información del tipo de "¿Estás seguro de que quieres hacer....?", lo que hace que se una función bastante utilizada.

Pues nada, aquí tenemos una pequeña rutina que utiliza la función MsgBox:


Sub MiMacro()
    MsgBox "Hola mundo", vbOkOnly + vbInformation, 
           "Mi segunda macro"
End Sub

Recuerda que para escribir la macro tienes que situarte en una hoja de módulo en Excel 95, o ir al editor de VB en Excel 97, y dentro de él seleccionar un módulo. Por ejemplo, podemos escribir esta macro debajo de la que hemos creado antes utilizando la "grabadora" de Excel.

Hola mundoSi ejecutamos esta macro, veremos que sale un cuadro de diálogo con el título "Mi segunda macro" y con el texto "Hola mundo", además de un icono que indica que es un cuadro de información, y el botón aceptar. Hemos llamado a MsgBox, pasándole como primer parámetro el texto del cuadro de mensaje, como segundo parámetro los botones e icono que queremos que tenga y como tercer parámetro el título del cuadro de diálogo. Como habrás podido observar los argumentos van separados por comas. También se pueden poner más parámetros para indicar qué fichero de ayuda queremos que se abra si el usuario pulsa F1 mientras está viendo el cuadro de diálogo. Si quieres más información sobre dichos parámetros, así como una lista de todas las opciones que puedes utilizar como segundo parámetro (distintos botones e iconos) utiliza la ayuda de Excel, que es bastante completa. La mejor forma de utilizar la ayuda es colocar el cursor sobre la instrucción sobre la que queremos buscar la ayuda y pulsar F1. Si Excel encuentra esa palabra en el archivo de ayuda, nos mostrará la página de ayuda sobre ella.

Otra pequeña macro que utiliza MsgBox:


Sub Macro3()
    If MsgBox("Pulsa Aceptar o Cancelar",
	       vbOKCancel) = vbOK Then
        MsgBox ("Has pulsado Aceptar")
    Else
        MsgBox ("Has pulsado Cancelar")
    End If
End Sub

Bueno, varias cosas nuevas. En primer lugar el "If - Then - Else - End If". Como su nombre indica, esta instrucción (la ayuda de Excel los llama enunciados) se utiliza para evaluar condiciones. Su forma general es: If <condición> Then .... Else .... End If

Si el resultado de la condición es verdadero, se ejecutan las instrucciones que hay entre el If y el Else. Si es falso, se ejecutan las instrucciones que hay entre el Else y el End If. El Else no es obligatorio, o sea que si no nos interesa ejecutar nada en caso de que la condición no sea verdadera, simplemente ponemos un End If y ya está.

RidondoVolvamos a nuestra función: lo que hacemos es llamar a la función MsgBox con un texto y un parámetros (vbOkCancel) indicando los botones que queremos que tenga. Hasta aquí todo claro. Lo único que cambia respecto al ejemplo anterior es que como hemos puesto MsgBox detrás del If, Excel nos obliga a poner los parámetros entre paréntesis. Lo que hacemos después es comprobar el valor que nos devuelve la función MsgBox una vez que el usuario ha cerrado el cuadro de diálogo. El usuario va a tener dos botones (Aceptar y Cancelar), y dependiendo de cuál de ellos pulse obtendremos un valor u otro, representados por Excel mediante unas constantes: vbOk si el usuario pulsa Aceptar, vbCancel si el usuario pulsa Cancelar, vbYes si el usuario pulsa Sí (que en este ejemplo no existe pero podemos ponerlo), etc. Como siempre, en la ayuda de Excel están todas los valores posibles que puede devolver MsgBox.

Bueno, entendido esto supongo que el resto de la macro es fácil de entender: lo que hace es mostrar un mensaje con dos botones (Aceptar y Cancelar), y dependiendo de lo que el usuario seleccione muestra otro mensaje informando al usuario de lo que ha pulsado. No es que sea demasiado útil pero nos ha servido para aprender algo más.

Vamos hacer otra macro un poco más complicada, que utilice la función MsgBox y las propiedades de los objetos que hemos aprendido antes:

Sub Macro4()
    If MsgBox("Información 
	sobre la celda activa: " & Chr(13) & _
           "Fórmula: " & ActiveCell.Formula 
           & Chr(13) & _ "Valor: " & ActiveCell.Value 
           & Chr(13) & Chr(13) & _ "Pulsa Aceptar 
           para borrar el contenido de la celda 
           activa " _ & "y Cancelar para dejarla como 
           está", _ vbOKCancel + vbInformation, 
           "Mi cuarta macro") = vbOK Then
       ActiveCell.Value = ""
    End If
End Sub

Bueno, hay varias cosas que explicar: con el caracter "_" al final de una línea queremos decirle a Excel que la línea continúa, pero lo vamos a escribir debajo (por razones de legibilidad). Es decir, es como si desde el "If" de la segunda línea hasta el "Then" de la séptima línea estuviese todo en la misma línea, pero si lo puesiésemos en la misma línea sería bastante difícil de leer.

El carácter "&" se utiliza para concatenar dos cadenas de caracteres. Por ejemplo, la cadena "Macedonia Magazine" es igual que la cadena "Macedonia " & "Magazine".

La función Chr() se utiliza para obtener el carácter representado por un código ASCII. No es demasiado utilizada, tan sólo nos interesa saber que código ASCII número 13 representa el cambio de línea, y en este caso lo utilizamos para empezar una nueva línea en el texto que vamos a presentar en el cuadro de diálogo.

Fíjate cómo obtenemos información sobre la celda activa utilizando las propiedades Formula y Value del objeto ActiveCell. Podemos observar que las propiedades Formula y Value son distintas cuando las leemos (una tiene la fórmula, y la otra tiene el valor) mientras que para dar un valor a la celda nos da lo mismo utilizar una u otra: la linea que dice ActiveCell.Value = "" puede sustituirse por ActiveCell.Formula = "", obteniendo el mismo resultado.

Para ejecutar esta rutina, vamos a probar el método de asignar a una tecla esta macro. Para ello vamos a Herramientas, Macro. De la lista de macros, seleccionamos ésta y pulsamos el botón "Opciones...", que nos llevará a una ventana donde aparecen varias opciones para nuestra macro. En este diálogo podemos decir a Excel que ponga la macro como una opción del menu de Herramientas, y también como tecla rápida. Podemos poner por ejemplo la tecla Ctrl-M. Ahora vamos a una hoja de cálculo, e introducimos en cualquier celda la fórmula "=5+2". Si pulsamos ahora las teclas Ctrl-M ejecutaremos nuestra macro y veremos lo siguiente:

Bueno, espero que haya quedado relativamente claro. Hasta ahora hemos aprendido lo que es una macro o rutina, cómo ejecutarla, unos conceptos básicos sobre objetos y la instrucción "If-Then-Else", una de las más utilizadas.

Vamos a avanzar un poco más, aprendiendo a utilizar otra instrucción muy útil, el bucle "For", y a profundizar un poco en el uso del objeto Range, que es seguramente el más utilizado. Después de haber hecho el típico programa "Hola mundo" (el primero que hemos hecho todos cuando hemos aprendido un lenguaje de programación) vamos a hacer ahora otro clásico: vamos a pedirle al usuario que nos de un número y le vamos a dar la tabla de multiplicar de ese número.

Aquí va la rutina completa, y luego la explicamos:


Sub TablaMultiplicar()
    Dim n, i As Integer
    Dim s As String
    Dim r As Range
    
    s = InputBox("Tabla de multiplicar del número: ",
                 "Título")
    If s <> "" Then
        n = Val(s)
        ActiveSheet.Range("C2").Value = "Tabla de 
        multiplicar del " & n
        Set r = ActiveSheet.Range("C4")
        For i = 0 To 10
            r.Offset(i, 0).Value = i
            r.Offset(i, 1).Value = i * n
        Next i
    End If
End Sub

Pulsa aquí para bajarte un fichero de Excel que contiene este ejemplo. Lo primero es la declaración de variables. Una variable es un espacio de memoria que reservamos para almacenar datos. Con la sentencia "Dim n,i as Integer" estamos diciendo que queremos reservar memoria para dos variables (n, i) de tipo entero, para almacenar números enteros. Igualmente en las siguientes líneas reservamos memoria para una variable de cadena (string), que almacenará cadenas de caracteres, y para una variable de tipo Range. En VBA no es obligatorio declarar las variables antes de utilizarlas, a no ser que en cada módulo escribamos al principio "Options Explicit", con lo que estaremos indicando a VBA que debe comprobar que todas las variables que utilicemos estén previamente declaradas. No voy a entrar en la eterna polémica de si es mejor declarar las variables o no hacerlo, pero personalmente creo que es mejor hacerlo, para que el tipo de datos que almacena cada variable esté claro y para evitar errores al escribir los nombres de variables que luego pueden ser difíciles de localizar.

GenioEn la siguiente línea utilizamos la función "InputBox", que sirve para mostrar un cuadro de diálogo simple en el que el usuario puede escribir un dato. El primer parámetro es el texto descriptivo que se mostrará en el cuadro de diálogo y el segundo parámetro es el título del cuadro de diálogo. El usuario puede utilizar el cuadro de edición del diálogo para introducir el dato que le pedimos y luego pulsar Aceptar o Cancelar. Si pulsa Aceptar, la función InputBox devuelve una cadena de caracteres con el dato introducido por el usuario. Si pulsa Cancelar, la función devuelve una cadena de caracteres vacía (""). Utilizamos la función InputBox para que el usuario nos diga qué tabla de multiplicar quiere, y almacenamos el valor devuelto por la función en la variable s, que previamente hemos declarado como una variable de tipo cadena de carácteres (string).

Después de llamar a InputBox, comprobamos que variable "s" no está vacía, lo que significa que el usuario ha escrito algo en el diálogo y luego ha pulsado Aceptar. Si "s" esta vacía, la rutina termina sin hacer nada más.

Nuestro siguiente paso es obtener el número que ha introducido el usuario. Es importante distinguir entre números y cadenas: en este momento tenemos la cadena de carácteres "s" que contiene la cadena introducida por el usuario, y como queremos hacer operaciones aritméticas necesitamos el número contenido en esa cadena. Por ejemplo, si el usuario ha escrito "3", la variable "s" contendrá una cadena de carácteres de un solo carácter ("3"), y lo que nosotros queremos obtener es el valor numérico 3. Para ello utilizamos la función Val(), que dada una cadena de carácteres no da su valor numérico: p.ej: Val("3") nos devuelve 3. El resultado de la función Val lo almacenamos en la variable n, que previamente hemos declarado como variable de tipo entero.

Como siempre suele suceder, existe la posibilidad de que el usuario haya escrito un valor con decimales o que haya escrito letras en lugar de números. En una macro más profesional deberíamos comprobar esas posibilidades para asegurarnos de que nuestra macro no sufre ningún error en caso de que el usuario introduzca algún dato inesperado, pero por ahora no vamos a meternos en líos de esos.

La siguiente línea debería ser fácil de entender a estas alturas: damos un valor a la propiedad "Value" del rango C2 de la hoja activa, al que accedemos utilizando "ActiveSheet.Range("C2")". Una pequeña recomendación: siempre que hagas referencia a rangos de hojas de cálculo desde VBA es recomendable utilizar nombres definidos de rango en lugar de referencias tipo C2. Por ejemplo, podemos dar a la celda C2 el nombre "Título tabla" y acceder a ella utilizando Range("Título tabla"). La ventaja de esto es que si luego queremos que en lugar de en la celda C2 lo escriba en cualquier otra celda sólo tenemos que cambiar el nombre, sin tocar el código.

En la siguiente línea utilizamos el enunciado "Set" para que la variable r (de tipo Range) apunte al rango C4 de la hoja activa.

Luego viene la sentencia "For - Next", que tiene varias formas, pero esta es la más sencilla: lo que hacemos es que la variable "i" (como siempre, previamente declarada como de tipo entero) tome los valores comprendidos entre el 0 y el 10 (ambos inclusive), y para cada uno de esos valores se ejecute el código comprendido entre las líneas For y Next. Es decir, las dos líneas que hay entre el For y el Next se van a ejecutar once veces: la primera vez que se ejecuten, la variable i tendrá el valor 0; la segunda vez, i tendrá el valor 1; y la última vez i tendrá el valor 10. El bucle "For - Next" es muy utilizado, y en VBA funciona de forma muy parecida a cualquier otro lenguaje de programación.

Las dos líneas que hay entre el For y el Next son prácticamente iguales. El método "Offset" es un método que se aplica a los objetos de tipo Range (como nuestra variable "r") para desplazar el rango al que apunta. El primer parámetro del método Offset es el número de filas que queremos desplazar el rango (positivo hacia abajo, negativo hacia arriba), y el segundo parámetro es el número de columnas que queremos desplazar el rango. Vamos a verlo con un ejemplo: si nuestra variable "r" apunta al rango C4:

r.Value = 1 Pone el valor 1 en la celda C4
r.Offset(1,0).Value = 2 Pone el valor 2 en la celda C5
r.Offset(-1,0).Value = 3 Pone el valor 3 en la celda C3
r.Offset(0,1).Value = 4 Pone el valor 4 en la celda D4
r.Offset(-1,-1).Value = 5 Pone el valor 5 en la celda B3

Las dos líneas de nuestra rutina lo que hacen es crear una tabla de dos columnas, poniendo en la primera columna los números del 0 al 10 (es decir, los valores que va tomando i cada vez que se ejecutan estas dos líneas) y en la segunda columna el resultado de multiplicar el valor de i por el número que nos ha indicado anteriormente el usuario (n).

Antes de terminar con este ejemplo hay que dejar claro que la tabla de multiplicar puede hacerse de forma mucho más sencilla y rápida sin utilizar macros, utilizando tan sólo funciones de hoja de cálculo, pero nos ha servido como ejemplo sencillo para aprender algunas cosas más sobre VBA.

Bueno, hasta aquí ha llegado la primera entrega de este curso. Con lo que hemos aprendido hasta aquí se pueden hacer ya algunas cosas. Que a nadie le de miedo hacer todos los experimentos que quiera, que es la mejor forma de aprender. También es muy útil consultar a menudo la ayuda de Excel, que es bastante completa. Espero que alguno de los que habéis llegado hasta aquí me escribáis diciéndome qué os ha parecido.





AULA MACEDONIA
a
MACEDONIA Magazine