Capítulo 1

53
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. Lo 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

Transcript of Capítulo 1

Page 1: Capítulo 1

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.

Lo 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.

Page 2: Capítulo 1

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").SelectEnd 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".

Page 3: Capítulo 1

Ejecutar una subrutina

Para ejecutar una rutina hay varios métodos. Con la opción "Herramientas, Macro..." Excel te lista todas las macros

disponibles y puedes seleccionar la que quieras y ejecutarla. Asignar una macro a una nueva opción del menú de Herramientas. Asignar una "tecla rápida" a la macro, que se ejecutará cada vez que

pulsemos esa tecla. Crear un botón y asignar a ese botón la rutina, de forma que ésta se ejecutará

cada vez que pulsemos el botón. Para crear un botón tenemos que mostrar la barra de herramientas de "Diálogo" (pulsa con el botón derecho sobre cualquier barra de herramientas, y en el menú que aparece selecciona "Diálogo" y verás que aparece la nueva barra de herramientas). En esa barra de herramientas hay un botón que sirve para colocar botones (valga la redundancia) en nuestra hoja. Pulsa ese botón y crea el tuyo en cualquier parte de una hoja de cálculo, con el tamaño que quieras. Luego pulsa sobre ese botón con el botón derecho y del menú contextual selecciona la opción "Asignar macro". Verás una lista de macros disponibles, selecciona la que acabamos de crear (Macro1). Ahora cada vez que pulsemos el botón se ejecutará la macro Macro1.

Mientras estamos editando una hoja de módulos, un método muy práctico de ejecutar las rutinas es situar el cursor dentro de una rutina y pulsar el botón de "Ejecutar macro" de la barra de herramientas de Visual Basic. Hay que tener cuidado con este método en Excel 95, porque en algunos casos puede dar errores: por ejemplo, con este método nuestra primera macro no funciona porque "ActiveCell" no existe, ya que estamos en una hoja de módulo, por lo que Excel nos dará un mensaje de error. En Excel 97 este problema no ocurre porque no existen hojas de módulo, sino módulos dentro del Visual Basic Editor.

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

Page 4: Capítulo 1

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.

Si 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 IfEnd 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á.

Volvamos 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.

Page 5: Capítulo 1

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 IfEnd 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.

Page 6: Capítulo 1

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 IfEnd 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.

En 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

Page 7: Capítulo 1

variable s, que previamente hemos declarado como una variable de tipo cadena de caracteres (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 C4r.Offset(1,0).Value = 2 Pone el valor 2 en la celda C5

Page 8: Capítulo 1

r.Offset(-1,0).Value = 3 Pone el valor 3 en la celda C3r.Offset(0,1).Value = 4 Pone el valor 4 en la celda D4r.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.

Capítulo 2. Celdas, rangos, libros y hojas.

En este capítulo vamos a aprender un poco más sobre cómo hacer referencia a celdas, rangos, hojas y libros. Supongo que todos estos conceptos están claros, que todo el mundo sabe lo que es una celda o un rango, o la diferencia entre un libro y una hoja.

Bueno, para entrar en calor vamos a hacer una pequeña rutina que pida al usuario un valor y luego sume ese valor a la celda activa.

Sub Sumar_A_Celda() Dim i As Double

If MsgBox("Esta macro pide al usuario un valor y lo suma a la celda activa.", _ vbOK, "Sumar a celda") = vbCancel Then Exit Sub i = Val(InputBox("Importe a sumar: ", "Sumar a celda activa")) ActiveCell.Value = ActiveCell.Value + i

End Sub

La primera línea es la declaración de la variable "i". Ya hemos comentado anteriormente lo que es la declaración de variables, lo único nuevo es el tipo de variable (double). Cuando declaramos una variable hay que indicar qué tipo de variable queremos que sea. Los tipos de variables más importantes son:

Integer Un valor entero, entre -32.768 y 32.767Long Un valor entero, entre -2.147.483.648 y 2.147.483.647

Page 9: Capítulo 1

Boolean Verdadero y FalsoSingle Un valor con decimales, con precisión simpleDouble Un valor con decimales, con precisión dobleString Un cadena de caracteresDate Una fechaObject Referencia a cualquier tipo de objeto de ExcelVariant Un variable que puede cambiar de tipo

En este caso declaramos la variable como Double, por si acaso al usuario se le ocurre meter un valor con decimales.

Siguiendo con nuestra rutina, primero presentamos al usuario un pequeño mensaje diciendo lo que vamos a hacer. Esto está explicado en la entrega anterior, no creo que necesite nada más. Si el usuario pulsa "Cancelar", salimos de la rutina y no hacemos nada.

En la siguiente línea obtenemos del usuario el valor que quiere sumar a la celda activa. La función InputBox ya la hemos visto antes, obtiene del usuario una entrada, pero en formato de cadena de caracteres. Como nosotros lo que queremos es un valor numérico, utilizamos la función Val() para convertir la cadena de caracteres proveniente de InputBox en un número. Lo ponemos todo en la misma línea, pero también se podía haber escrito en dos líneas:

Dim s as String s = InputBox("Importe a sumar: ", "Sumar a celda activa") i = Val(s)

Bueno, seguramente queda más claro que de la otra forma, pero normalmente se escribe de la primera forma. Cada uno que lo escriba como quiera, tampoco tiene demasiada trascendencia.

La última línea es la que hace realmente la suma, dando valor a la propiedad Value de ActiveCell. Ya hemos visto en la entrega anterior lo que es ActiveCell. Una aclaración sobre ActiveCell y ActiveSheet (que también vimos en la entrega anterior): en realidad, ActiveCell no es un objeto, sino que es una "propiedad" de un objeto especial llamado Application, pero cuando escribimos "ActiveCell" Excel entiende que estamos escribiendo "Application.ActiveCell". Application es un objeto que representa la aplicación Excel completa. A través de Application se puede acceder a todas las opciones de la aplicación (las que podemos cambiar a través de Herramientas, Opciones), acceder a las funciones de hoja de cálculo (SUMA, PROMEDIO, etc) y también podemos obtener objetos que referencian a la celda activa (ActiveCell), la hoja activa (ActiveSheet), el libro activo (ActiveWorkbook), etc.

Un pequeño ejemplo del uso del objeto Application: para mostrar y ocultar la barra de estado (la que aparece en la parte de abajo, debajo de las etiquetas de las hojas), podemos usar el siguiente código:

Para ocultar la barra de estado: Application.DisplayStatusBar = False

Para volver a mostrar la barra de estado: Application.DisplayStatusBar = True

Page 10: Capítulo 1

El objeto Application tiene un montón de propiedades y métodos, que están muy bien explicados en la ayuda de Excel, y su uso es bastante sencillo.

Siguiendo con la última línea de la rutina, podrás comprobar que utilizamos la propiedad Value de ActiveCell. Si hubiésemos utilizado la propiedad Formula en lugar de Value, la rutina tendría que ser un poco distinta. Utilizando Value, estamos dando a la celda activa un valor directamente, es decir, si miras el contenido de la celda verás que no hay ninguna fórmula; la suma la ha hecho nuestra rutina, y ha puesto en la celda el resultado de dicha suma.

Sin embargo, si queremos que la fórmula de la suma quede en la celda debemos usar la propiedad Formula. La propiedad Formula es una "cadena de caracteres", que incluye todo lo que se escribiría normalmente en una celda de una hoja de cálculo para introducir una fórmula (incluyendo el signo "=" al principio). Por ejemplo, si queremos poner en la celda A2 una fórmula que nos de el doble del valor de la celda A1, haremos:

Range("A2").Formula = "=A1*2"

Como es una cadena de caracteres, hay que rodearla con comillas dobles, y entre éstas ponemos la fórmula tal como lo haríamos en la hoja de cálculo. Tras esta explicación, si queremos cambiar nuestra rutina para introducir la fómula de suma en la celda, nuestro primer intento sería escribir:

ActiveCell.Formula = ActiveCell.Formula + i

Si ejecutamos este código veremos que el resultado puede variar dependiendo de lo que contenga la celda activa:

Si la celda activa contiene un número (no una fórmula), el resultado es el mismo que antes. La razón es que como no hay ninguna fórmula ActiveCell.Formula devuelve un número, igual que ActiveCell.Value. Luego le sumamos nuestro valor y asignamos el valor resultante como fórmula de la celda.

Si la celda activa contiene una fórmula, el resultado es que la macro se para con un error. Esto es debido a que ActiveCell.Fórmula nos devuelve una cadena de caracteres (por ejemplo, la cadena "=A1*2"), y luego estamos intentando sumar un número (i) a una cadena de caracteres, cosa que evidentemente no se puede hacer y Excel nos da un error de tipos de datos incompatibles.

Para conseguir lo que realmente queremos (introducir una fórmula en la celda), debemos asignar a ActiveCell.Formula una cadena de caracteres con una fórmula escrita correctamente. Vamos a intentarlo:

ActiveCell.Formula = ActiveCell.Formula & "+" & i

El operador & ya lo vimos en la primera entrega, se utiliza para concatenar cadenas de caracteres. Partimos de la fórmula que actualmente tiene la celda activa (por ejemplo, "=A1*2") y luego le añadimos un signo "+" y luego nuestro valor (i), con lo que la fórmula pasará a ser "=A1*2+3" (si i tiene el valor 3).

Page 11: Capítulo 1

El problema que se nos presenta ahora es que si en la celda activa no hay una celda, sino un valor (por ejemplo, 2), nosotros asignaremos a ActiveCell.Formula la cadena "2+3" (si i tiene el valor 3). ¿Veis el error? Evidentemente el error es que falta el signo "=" al principio de la fórmula para decirle a Excel que es una fórmula. O sea que deberíamos añadir delante de la fórmula un "=", lo que podemos hacer de la siguiente forma:

ActiveCell.Formula = "=" & ActiveCell.Formula & "+" & i

¿Cuál es el problema ahora? Pues que si la celda activa tiene una fórmula nos encontramos con que nuestra fórmula definitiva tiene dos signos "=" al principio, uno el que ya tenía y otro el que le hemos puesto nosotros. El resultado es que introducimos una fórmula incorrecta y Excel nos vuelve a dar un error.

Bueno, creo que he montado un pequeño lío, pero en realidad no tiene ninguna dificultad. Lo que hay que hacer es comprobar si en la celda activa hay una fórmula (esto se puede hacer mirando si el primer carácter es el signo "=", utilizando por ejemplo la función Left). Si hay una fórmula, sólo añadimos la parte del final, y si no hay una fórmula añadimos primero un signo "=" y luego la parte del final. Esto queda como ejercicio, y si no te sale me escribes y lo comentamos.

Pues aparte de todo este lío ya lo hemos visto todo. Si ejecutas la rutina Sumar_A_Celda() comprobarás que primero te pide un valor y luego suma ese valor a la celda activa. Por cierto, que nadie piense que esta macro es ninguna maravilla, porque lo mismo que hace se puede hacer más rápido utilizando "Pegado especial..", que además es capaz de restar, multiplicar y dividir. Ya llegaremos a eso también, pero para ir aprendiendo un poco no nos viene mal.

Ahora vamos a avanzar otro paso: la rutina anterior sumaba un valor a la celda activa, y ahora vamos a sumar ese valor a todo el rango que seleccione el usuario. Como siempre, aquí va la rutina completa, luego la explicamos:

Sub Sumar_A_Rango() Dim i As Double Dim h As Object If MsgBox("Esta macro pide al usuario un valor y lo

suma a todas las celdas " & _ Chr(13) & "del rango seleccionado.", vbOK, "Copiar

celda izquierda") _ = vbCancel Then Exit Sub i = Val(InputBox("Importe a sumar: ", "Sumar a rango seleccionado")) For Each h In Selection.Cells h.Value = h.Value + i Next hEnd Sub

Lo primero que hacemos es declarar las variables. La primera variable (i), es de tipo Double, al igual que en la rutina anterior. La segunda variable (h) la declaramos como una variable de tipo Object, para que apunte a cualquier tipo de objeto de Excel (una hoja, un rango, una celda, etc.)

Las dos siguientes líneas son iguales que antes: primero presentamos un pequeño mensaje al usuario, y luego obtenemos el valor y convertimos la cadena a un valor numérico.

Page 12: Capítulo 1

En las tres siguientes líneas está todo lo nuevo. Vamos por pasos: Selection es una propiedad del objeto Application, o sea que al escribir Selection Excel supone que estamos escribiendo Application.Selection. Pues bien, la propiedad Selection nos devuelve el rango que está seleccionado en la hoja activa, es decir, un objeto de tipo Range.

Con Selection obtenemos un objeto de tipo Range que apunta al rango seleccionado de la hoja activa. Si accedemos a la propiedad Cells de ese objeto Range, obtendremos un "conjunto" de todas las celdas de ese rango.

¿Que es un conjunto? Un conjunto es un objeto que contiene otros objetos, generalmente del mismo tipo (la definición la he copiado de la ayuda de Windows). La propiedad Cells de un objeto Range nos devuelve un conjunto que contiene todas las celdas de ese rango.Luego viene una instrucción "For". En la entrega anterior vimos una instrucción For, pero un poco distinta a esta. En ese caso lo que hacíamos era dar a una variable distintos valores, desde el 1 hasta el 10, y para cada valor de la variable ejecutábamos unas instrucciones. Análogamente, en esta ocasión vamos a dar a la variable "h" (de tipo Object) unos valores, y para cada valor de "h" vamos a ejecutar una instrucción.

Para dar los distintos valores a "h" vamos a utilizar la instrucción "For Each", que "repite un grupo de enunciados para cada elemento de una matriz o de un conjunto". El conjunto que vamos a utilizar es Selection.Cells, que como sabemos son todas las celdas del rango seleccionado. Es decir, que con

For Each h In Selection.Cells h.Value = h.Value + 1Next h

lo que hacemos es ejecutar una instrucción para cada una de las celdas del conjunto Selection.Cells. La primera vez que se ejecute la instrucción de dentro del buble, h representará la primera celda del conjunto de celdas, la segunda vez representará la segunda celda del conjunto, etc. En este caso lo que hemos hecho ha sido sumar el valor uno a todas las celdas del rango seleccionado.

La instrucción que va dentro del bucle es la misma que en el ejemplo anterior; tan sólo fíjate que utilizamos "h" en lugar de ActiveCell.

Vamos a hacer otro pequeño ejemplo del uso de "For Each" y de conjuntos. En esta ocasión vamos a cambiar el nombre de todas las hojas del libro activo. Para obtener una referencia al libro activo utilizaremos la propiedad ActiveWorkbook del objeto Application. Para acceder a todas las hojas de cálculo del libro activo, utilizaremos la propiedad Worksheets de dicho objeto, ActiveWorkbook. He utilizado la propiedad Worksheets porque esta nos devuelve sólo las hojas de cálculo (no las hojas de gráficos, módulos, etc.). Si queremos acceder a todas las hojas (de cualquier tipo) del libro, utilizaremos la propiedad Sheets, que funciona igual que Worksheets.

Aquí va la rutina de ejemplo:

Sub NombresHojas() Dim h As Object Dim i As Integer

i = 15 For Each h In ActiveWorkbook.Worksheets

Page 13: Capítulo 1

h.Name = "Hoja " & i i = i + 1 Next hEnd Sub

Lo que hace esta rutina es cambiar los nombres de las hojas de cálculo del libro activo, poniéndoles los nombres "Hoja15", "Hoja16", etc. No es que sea una rutina demasiado útil, pero como siempre sirve para aprender un poco.

Como siempre, empezamos con la declaración de variables. Luego le damos a la variable "i" el valor 15, porque nos da la gana, podíamos haberle dado cualquier otro.

Luego viene lo que nos interesa, el "For Each". Para cada hoja de cálculo (Worksheets) del libro activo (ActiveWorkbook) vamos a ejecutar las dos instrucciones que están dentro del bucle.

Para cambiar el nombre de una hoja utilizamos la propiedad Name. Luego incrementamos el valor de "i" para dar el nombre a la hoja siguiente. (Si intentamos dar a dos hojas el mismo nombre Excel nos dará un mensaje de error)

Bueno, otra rutina para jugar un poco con hojas y celdas:

Sub ListaHojas() Dim h As Object Dim r As Range If MsgBox("Esta macro crea en la celda

activa una lista con los nombres de todas" & _ Chr(13) & "las hojas del libro activo.", vbOK,

"Lista Hojas") = vbCancel _ Then Exit Sub Set r = ActiveCell For Each h In ActiveWorkbook.Sheets r.Value = h.Name r.Offset(0, 1).Value = TypeName(h) Set r = r.Offset(1, 0) Next hEnd Sub

Lo que hace esta rutina es crear en la hoja de cálculo activa una tabla con los nombres de todas las hojas del libro. Primero, con "Set r = ActiveCell", hacemos que la variable "r" apunte a la celda activa.

Luego viene el bucle "For Each / Next", que al igual que en el ejemplo anterior hace que el código entre estas dos líneas se ejecute una vez para cada hoja del libro. La única diferencia es que en el ejemplo anterior utilizábamos "ActiveWorkbook.Worksheets" (que pasa por todas las hojas de "cálculo" del libro) y aquí "ActiveWorkbook.Sheets" (que pasa por todas las hojas del libro, de todo tipo).

Primero damos a la celda "r" el nombre de la primera hoja del libro. En la siguiente línea, ponemos en a celda de la derecha de "r" (con el Offset(0,1)) el tipo de hoja de que se trata, utilizando la función "TypeName(h)": esta función devuelve una cadena de carácteres que proporciona información sobre la variable "h".

Page 14: Capítulo 1

En la siguiente línea, utilizando otra vez Offset, "movemos" la variable "r" para que apunte a la celda inferior. Y así, vuelta a empezar.

Y para terminar, vamos a aprender a utilizar el método Copy, que se aplica a objetos de Excel que puedan ser copiados, como por ejemplo un objeto de tipo Range, aunque también a otros objetos como hojas enteras o gráficos.

Lo que vamos a hacer es copiar en la celda activa el contenido de la celda de su izquierda:

Sub Copiar_CeldaIzquierda() If MsgBox("Esta macro copia en la celda

activa el contenido de la celda situada" & _ Chr(13) & "a su izquierda.", vbOK, "Copiar celda

izquierda") = vbCancel Then Exit Sub ActiveCell.Offset(0, -1).Copy ActiveCellEnd Sub

La sintaxis de Copy es muy sencilla: se ejecuta el método Copy sobre el rango de "origen", es decir, el que queremos copiar. En el ejemplo, hacemos "ActiveCell.Offset(0,-1).Copy", ya que queremos copiar la celda que está a la izquierda de la celda activa.

El parámetro del método Copy indica el rango de "destino" para la copia. En nuestro ejemplo ponemos "ActiveCell", ya que queremos que lo que hemos copiado se copie en la celda activa. Si omitimos el parámetro del método Copy la copia se hará en el "Portapapeles", y luego deberemos utilizar otros métodos como "Paste" o "PasteSpecial" para pegar el contenido del portapapeles en otra celda.

Hasta aquí llega esta segunda entrega del curso. En este capítulo hemos aprendido a trabajar con celdas, rangos, libros y hojas, que es una de las partes más útiles de la programación en Excel, permitiéndonos hacer cualquier operación (mover, copiar, borrar, hacer operaciones aritméticas, etc) con los datos de una hoja de cálculo.

Capítulo 3. Cuadros de diálogo (Userforms).

Este capítulo va a tratar sobre los cuadros de diálogo, que se utilizan para obtener información del usuario. Una aclaración respecto a versiones: uno de los cambios más importantes de Excel 95 a Excel 97 en el apartado de programación es la parte de cuadros de diálogo. La verdad es que hay muchas diferencias entre ambos y eso hace imposible hablar de las dos versiones a la vez, por lo que este capítulo está dirigido sólo a Excel 97.

Todos los ejemplos de este capítulo están incluídos en este fichero: Excel3.xls

(117kbs)

Los cuadros de diálogo en Office 97 son mucho más potentes que en la versión anterior. Se han añadido muchas opciones, como la posibilidad de definir eventos, utilizar controles ActiveX además de los incluidos en Excel (si no sabes qué es un control ActiveX no tiene demasiada importancia, es un tema avanzado que quizá algún día tratemos), etc.Nuestro primer cuadro de diálogo va a ser muy sencillo: vamos a presentar un cuadro de diálogo en el que el usuario puede introducir un número, y si pulsa "Aceptar"

Page 15: Capítulo 1

copiaremos el número introducido en la celda activa. Si el usuario pulsa "Cancelar" no haremos nada.Lo primero es ir al editor de Visual Basic, utilizando la opción "Herramientas, Macro, Editor de Visual Basic", o simplemente pulsando Alt-F11.En la parte izquierda de la pantalla tendremos el "Explorador de Proyectos" y la ventana de "Propiedades". Igual que antes, si no puedes ver estas ventanas utiliza el menú "Ver" para hacer que aparezcan. En el "Explorador de Proyectos" aparecen todos los "proyectos" de VBA: cada libro que tengamos abierto es un proyecto. Dentro de cada libro aparecen todas las hojas del libro y también los módulos y cuadros de diálogo que crearemos más adelante.En la ventana de "Propiedades" aparecen las propiedades del objeto que tengamos seleccionado en ese momento. Supongo que a estas alturas ya debe estar claro el concepto de "propiedad" de un objeto. Por ejemplo, vamos a ir a un proyecto de VBA en el "Explorador de Proyectos". Dentro de él veremos las hojas de cálculo del libro, y vamos a seleccionar una de ellas. En la ventana de "Propiedades" van a aparecer las propiedades de la hoja seleccionada. Por ejemplo, la primera propiedad que vemos es la propiedad Name, que ya conocemos. Podemos utilizar la ventana de "Propiedades" para cambiar las propiedades del objeto seleccionado.Ahora para crear nuestro cuadro de diálogo vamos a utilizar la opción "Insertar, Userform" (Userform es el nombre que da Excel 97 a los cuadros de diálogo).En este momento vemos en la parte derecha un cuadro de diálogo vacío, y por otro lado veremos el "Cuadro de herramientas", en el que están todos los controles que podemos poner en el cuadro de diálogo. Si no aparece el Cuadro de Herramientas utiliza la opción "Ver, Cuadro de herramientas" para que aparezca.Los controles del "Cuadro de herramientas" son los típicos de cualquier cuadro de diálogo que podemos ver en cualquier aplicación de Windows:

Etiqueta: para mostrar un texto en el cuadro de diálogo. El usuario no puede

editarlo. Cuadro de texto: para que el usuario introduzca un texto. Cuadro combinado: el clásico control de persiana para que el usuario seleccione

una opción entre varias. Cuadro de lista

presentamos. Casilla de verificación: verdadero o falso Botón de opción

varias. Botón de comando

"Cancelar" Marco: para agrupar varios controles. Su uso es básicamente por razones

estéticas. Como puedes ver en el diálogo de ejemplo un marco puede tener distintas

apariencias. Primero vamos a ver las propiedades del objeto UserForm. Para ello seleccionamos el Userform de la parte derecha simplemente pulsándolo con el ratón. En la parte inferior izquierda, en la ventana de Propiedades, tenemos la lista de propiedades del objeto UserForm. Utilizando esta ventana podemos cambiar el valor de cualquier propiedad del Userform. Algunas de las propiedades más importantes son:

Name: el nombre con el que vamos a identificar el UserForm. Tiene que ser único y no puede tener espacios ni otros caracteres raros. Yo suelo ponerles un nombre que empiece por "uf" (por ejemplo, ufDatosPersonales), porque así

Page 16: Capítulo 1

cuando en el código VB haga una referencia a este objeto sé que se trata de un objeto UserForm.

Caption: es el título que el usuario verá en el cuadro de diálogo. Se puede poner cualquier texto, incluyendo espacios.

BackColor: el color de fondo del cuadro de diálogo. Por defecto es el color gris que suelen tener todos los cuadros de diálogo en Windows.

ForeColor: el color de primer plano, es decir, del texto que aparezca en el cuadro de diálogo.

Font: el tipo de letra por defecto para el cuadro de diálogo. Este es el tipo de letra que tendrán todos los controles que insertemos en el cuadro de diálogo, pero si luego queremos cambiarlo para cualquier control puede hacerse.

StartupPosition: la posición en la que aparecerá el cuadro de diálogo. Si le damos el valor "CenterScreen" el diálogo saldrá en el centro de la pantalla.

SpecialEffect: para cambiar un poco los bordes del cuadro de diálogo. Picture, PictureAlignment, PictureSizeMode, PictureTiling: se utilizan para

poner un dibujo como fondo del cuadro de diálogo. Hay más propiedades, pero su uso es bastante sencillo, y consultando la ayuda encontrarás la descripción de todas las propiedades.Vamos con nuestro diálogo: lo primero es cambiarle el nombre; vamos a la ventana de Propiedades y en la propiedad Name, escribimos por ejemplo "ufPrimero". Luego en la propiedad "Caption" escribiremos "Mi primer UserForm". Las demás propiedades las dejamos como están, aunque si quieres cambiar alguna que afecte a la presentación del diálogo (color de fondo, efectos especiales, etc) puedes hacerlo tranquilamente.En cualquier momento puedes probar tu cuadro de diálogo seleccionándolo con el ratón y utilizando la opción "Ejecutar, Ejecutar Sub/Userform" (o más rápido pulsando

F5 o el botón de ejecutar ). Para cerrar el diálogo tendrás que utilizar la "X" que aparece en la parte superior derecha, porque todavía no hemos añadido ningún botón para cerrar el diálogo.Como hemos dicho antes, en nuestro cuadro de diálogo queremos que el usuario escriba un número. Para que pueda hacerlo, tendremos que poner un cuadro de texto en el diálogo. Para ello pulsamos en el UserForm para que aparezca el "Cuadro

de Herramientas" y en éste pulsamos sobre el control "Cuadro de Texto" . Una vez seleccionado el "Cuadro de Texto" pulsamos en cualquier parte del UserForm y veremos que aparece un cuadro de edición. Podemos utilizar el ratón para moverlo y cambiarle el tamaño.Pulsando con el ratón, seleccionaremos el cuadro de edición, y como de costumbre veremos que en la ventana de "Propiedades" aparecen todas las propiedades del objeto "Cuadro de Texto" (TextBox en inglés), entre las que se encuentran:

Name: el nombre del objeto. Como antes, no puede incluir espacios ni caracteres especiales. Yo suelo utilizar nombres que empiecen por "tb", para identificar estos objetos como un TextBox, pero se puede utilizar cualquier nombre.

Text: es el texto que va dentro del cuadro de edición, es decir, el que ha escrito el usuario.

TextAlign: alineación del texto dentro del cuadro de diálogo. Normalmente si lo que queremos es que el usuario introduzca una cadena de texto se suele alinear a la izquierda, y si queremos que introduzca números se suele alinear a la derecha.

MultiLine: los valores posibles son verdadero y falso, indicando si queremos que el control permita al usuario escribir más de una línea o no.

Las propiedas sobre la apariencia del control son parecidas a las que hemos visto antes (BackColor, ForeColor, SpecialEffects). El resto de propiedades se pueden consultar en la ayuda. Aunque parezca que nos estamos dejando muchas cosas, una

Page 17: Capítulo 1

vez que empezamos a tener claras las cosas el utilizar propiedades que no hemos usado nunca es muy sencillo. O sea, que por ahora nos centramos en lo básico.Bueno, ahora vamos a nuestro cuadro de diálogo. Seleccionamos nuestro cuadro de edición, lo colocamos en una posición que nos guste, y vamos a las propiedades. Primero la propiedad Name, que en este caso vamos a dejar tal como está, TextBox1. No suele ser aconsejable dejar estos nombres, porque si tienes varios cuadros de edición en un diálogo al final no sabes a cuál te estás refiriendo, pero como en este caso sólo vamos a tener un cuadro de edición no nos importa demasiado. Ahora vamos a la propiedad "TextAlign" y vamos a seleccionar la opción "fmTextAlignRight" para alinear el texto a la derecha, ya que lo que queremos es que le usuario introduzca un número. Por ahora no vamos a hacer nada más con este control.Si ejecutamos el cuadro de diálogo veremos que podemos introducir un valor en el cuadro de edición que hemos creado, pero aparte de eso no podemos hacer mucho más.Lo siguiente que vamos a hacer es poner un texto descriptivo para el cuadro de edición. Para ello seleccionamos del "Cuadro de herramientas" el control "Etiqueta"

, y pulsamos en el UserForm para crear un control del tipo etiqueta. Utilizando el ratón le podemos cambiar el tamaño y moverlo, para ponerlo a la izquierda del control de edición que hemos creado antes.En la ventana de propiedades de nuestro nuevo control (recuerda que tienes que seleccionarlo para poder ver sus propiedades en la ventana de propiedades) veremos como siempre la lista de propiedades. La propiedad Name la vamos a dejar como está, ya que no vamos a referirnos a este control en el código, y no nos interesa su nombre: normalmente los controles de etiqueta se utilizan sólo para poner un texto en el diálogo, y no se suelen referenciar desde el código VB. La propiedad que nos interesa es "Caption", en la que escribiremos el texto que queremos que aparezca en el cuadro de diálogo, por ejemplo "Escribe un número:". Si colocamos bien los dos controles (utilizando por ejemplo la opción "Formato, Alinear, Medio), ya tenemos un diálogo algo más completo.Lo típico en estos cuadros de diálogo es que en la parte inferior haya dos botones, uno para "Aceptar" y el otro para "Cancelar". Vamos a colocar estos dos botones, empezando por el de "Cancelar" que es un poco más fácil.Como antes, vamos al "Cuadro de Herramientas" y seleccionamos el control "Botón

de comando" . Pulsamos sobre el UserForm y hemos creado nuestro primer botón, que podemos mover y cambiar de tamaño utilizando el ratón. Una vez seleccionado nuestro nuevo control podremos ver sus propiedades en la ventana de "Propiedades":

Name: el nombre del control. Vamos a darle el nombre "cbCancel" (cb viene de CommandButton).

Caption: el texto del botón. Lógicamente, vamos a poner "Cancelar". Cancel: puede ser verdadero o falso. Sólo puede haber un control en el cuadro

de diálogo con la propiedad Cancel establecida como verdadero. Si le damos a Cancel el valor verdadero, cuando se esté ejecutando el cuadro de diálogo si el usuario pulsa "Escape" será como si hubiese pulsado con el ratón sobre este botón. En este caso nos interesa que ocurra, o sea que vamos a darle el valor verdadero.

Default: verdadero o falso, indica si el botón es el botón por defecto del cuadro de diálogo. Si el usuario pulsa "Enter" cuando está viendo el diálogo será como si pulsa con el ratón sobre el botón que tenga la propiedad Default (sólo puede haber uno). En este caso vamos a dejar la propiedad en False porque queremos que el botón por defecto sea el de "Aceptar", que crearemos más adelante.

Page 18: Capítulo 1

Por ahora dejamos el resto de propiedades de los botones. Bueno, hasta ahora le hemos dado a nuestro botón el nombre "cbCancel", le hemos puesto el texto "Cancelar" y hemos dado el valor "Verdadero" a la propiedad "Cancel".Si ejecutamos el cuadro de diálogo veremos que tenemos un botón muy bonito, pero que no hace absolutamente nada. Para que haga algo tenemos que meternos con un concepto muy importante de la programación orientada a objetos, los Eventos.A estas alturas ya deberían estar claros los conceptos de Objeto, Propiedad y Método. En Excel, un objeto es una variable que representa cualquier elemento de Excel, como un rango, un libro, una celda, o un UserForm. Todos los objetos tienen propiedades (como Cell.Value, Workbook.Name o UserForm.BackColor), y métodos (como Range.ClearContents o UserForm.Show).Además de propiedades y métodos los objetos tienen también "eventos". He mirado en la ayuda y no he encontrado una definición de evento, y tampoco me atrevo a dar una, pero voy a ver si puedo explicar el concepto. Imaginemos que tenemos un control, como por ejemplo el control de edición que hemos colocado en nuestro diálogo. Cuando sucede un "evento" de los que este control "entiende", Excel llamará a una función con un nombre especial, siempre que hayamos definido esa función (si no la hemos definido, no pasa nada, el "evento" se ignora). Un ejemplo de evento es que el usuario mueva el ratón por encima de nuestro control. Cada vez que el ratón se mueve se produce un evento "MouseMove", y entonces Excel llamará a la rutina TextBox1_MouseMove( ... ), en caso de que hayamos definido esa rutina, lo que haremos en caso de que nos interese hacer algo cada vez que el ratón pase por encima de nuestro control. El nombre de la rutina es especial: primero va el nombre del control (recuerda que lo habíamos dejado tal como nos lo había puesto Excel, TextBox1), luego un carácter de subrayado ("_"), y luego el nombre del evento.Otro ejemplo de evento: queremos que el usuario introduzca un número en el cuadro de edición, pero si lo probamos veremos que se puede escribir cualquier carácter que no sea un número. Cada vez que el usuario pulsa una tecla se produce el evento "KeyPress", que podemos utilizar para ignorar la tecla pulsada por el usuario si éste pulsa una tecla que no es un número. Más adelante veremos cómo se hace.Bueno, no sé si ha quedado muy claro, pero creo que con un poco de práctica espero que sí. Dominar los conceptos de objeto, propiedad, método y evento es muy importante, pero no sólo para programación en Visual Basic for Applications, sino que estos conceptos son básicos en todos los lenguajes de programación orientada a objetos (Visual Basic, Borland Delphi, Java, etc.). De hecho, si dominas esos conceptos con cuatro cosas más podrás programar en cualquiera de esos otros lenguajes.Bueno, sigamos con los eventos. Vamos a centrarnos ahora en nuestro botón de "Cancelar". El evento más normal para un botón es que el usuario lo pulse con el ratón (o con el teclado). Cuando esto ocurra, se generará un evento Click, y llamará a la rutina cbCancelar_Click(). (cbCancelar es el nombre que habíamos dado al control, y Click es el nombre del evento). Lo más fácil para crear un evento es seleccionar un control y luego pulsar el botón derecho y seleccionar la opción "Ver Código". Veremos una página de código VB en la que Excel habrá escrito la cabecera de un evento para dicho control (la verdad es que no sé cuál de los eventos coge, supongo que cogerá el más utilizado). En nuestro caso, si pulsamos sobre el botón "Cancelar" con el botón derecho y luego "Ver código" en la página de código veremos lo siguiente:Private Sub cbCancelar_Click()

End SubExcel nos ha creado la cabecera para la función que queremos crear. En este caso la función no tiene ningún parámetro, pero en otros eventos la función tiene una lista de parámetros, y Excel también nos los pone en la cabecera.

Page 19: Capítulo 1

Otra cosa, la página de código que estamos viendo es como un módulo normal en el que escribimos nuestro código, con la particularidad de que no sale en la lista de módulos en el "Explorador de Proyectos", ya que es un módulo asociado al Userform.Para crear una función para cualquier otro evento tenemos en la parte superior de la ventana de código dos "persianas". En la persiana de la izquierda tenemos el objeto sobre el que queremos definir una función para un evento. En la persiana de la derecha tenemos todos los eventos que pueden ocurrir para el control seleccionado en la persiana de la izquierda. Si queremos definir la función para otro evento lo único que tenemos que hacer es seleccionar otro evento en esta persiana, y Excel insertará en el código la cabecera para la función que se va a ejecutar cuando se de ese evento.Bueno, lo que queremos hacer cuando el usuario pulsa el botón de Cancelar es simplemente cerrar el cuadro de diálogo. Tendremos que cerrar el cuadro de diálogo cuando Excel nos avise de que ha ocurrido un evento Click, es decir, dentro de la función cbCancelar_Click().La instrucción que se utiliza para cerrar el UserForm es "Unload", que sirve para quitar un objeto de la memoria. La instrucción Unload requiere un parámetro, que utilizaremos para indicarle cuál es el objeto. En nuestro caso utilizaremos la palabra clave "Me", que apunta al objeto en el que se está ejecutando el código, es decir, nuestro UserForm.Nuestro "manejador de eventos" para el evento Click del botón cbCancel quedaría así:Private Sub cbCancelar_Click() Unload MeEnd SubCuando el usuario pulse el botón de Cancelar se generará un evento Click, y Excel llamará a nuestra función, que utilizará la instrucción Unload para cerrar el diálogo. Fíjate en que si pulsas la tecla "Escape" el diálogo se cierra igual que si hubieses pulsado con el ratón sobre el botón: esto es debido a que hemos dado el valor verdadero a la propiedad "Cancel" del botón Cancelar.Después de probar el cuadro de diálogo y comprobar que nuestro botón de Cancelar funciona perfectamente nos queda añadir el botón de Aceptar. Para crear el botón seleccionamos en el "Cuadro de Herramientas" el "Botón de comando" y lo colocamos en el UserForm. Luego le ponemos su nombre (cbAceptar por ejemplo), cambiamos su texto (ponemos Aceptar) y le damos el valor "Verdadero" a la propiedad Default para que si el usuario pulsa Enter sea como si hubiese pulsado con el ratón sobre el botón.Ahora nos queda todo el tema de los eventos. El procedimiento es el mismo que con el botón de Cancelar, con la única diferencia de que antes de cerrar el cuadro de diálogo (con la instrucción Unload) deberemos hacer lo que queremos que nuestro diálogo haga, es decir, copiar el contenido del cuadro de edición TextBox1. La función sería la siguiente:Private Sub cbAceptar_Click() ActiveCell.Value = TextBox1.Value Unload MeEnd SubEsta función es prácticamente igual que la que hemos escrito para el botón Cancelar, con la excepción de que antes de cerrar el cuadro de diálogo escribimos otra línea, que se encarga de copiar en la celda activa (ActiveCell) el contenido del cuadro de edición. Fíjate como accedemos al contenido del cuadro de edición, a través del

Page 20: Capítulo 1

nombre del control (TextBox1) y su propiedad Value, que nos devuelve el valor numérico de lo que se ha introducido en el control (si hay caracteres no numéricos la propiedad Value nos devolverá el valor 0).Si probamos ahora el cuadro de diálogo veremos que ya funciona perfectamente, ya hemos conseguido que nuestro primer UserForm funcione. El único problema que tiene es que en el cuadro de edición el usuario puede escribir cualquier caracter además de números. Para evitar esto ya he adelantado antes que hay que utilizar el evento KeyPress del cuadro de edición, pero eso lo veremos más adelante. - El segundo cuadro de diálogo.Vamos a hacer otro cuadro de diálogo: tenemos en una hoja de cálculo una celda con el nombre de una persona y otra celda con el apellido. Queremos crear un Userform que permita al usuario editar ese nombre y apellido, y si pulsa Aceptar en el cuadro de diálogo los valores de esas celdas deben actualizarse con lo introducido por el usuario.Si te fijas en el fichero de ejemplo verás las dos celdas que incluyen el nombre y el apellido. A estas celdas les he dado el nombre "rngNombre" y "rngApellido", respectivamente. Cuando hagamos referencias a celdas de hojas de cálculo en nuestro código es muy conveniente utilizar nombres de rangos en lugar de referencias absolutas (como por ejemplo C12), ya que si utilizamos nombres de rangos y movemos esas celdas no tenemos que hacer ningún cambio en el código, lo que deberemos hacer si utilizamos referencias absolutas.Repetimos los pasos anteriores:

Crear el UserForm, utilizando "Insertar, Userform" en el editor de Visual Basic. Vamos a dar al UserForm el nombre "ufDatosPersonales"

Insertamos dos cuadros de texto, uno para el nombre y otro para el apellido, a los que daremos los nombres tbNombre y tbApellido.

Insertamos dos etiquetas que colocaremos a la izquierda de cada uno de los dos cuadros de texto.

Insertamos un botón para Cancelar el cuadro de diálogo, al que cambiaremos el nombre a "cbCancelar", el texto a "Cancelar" (utilizando la propiedad Caption") y daremos a la propiedad Cancel el valor Verdadero.

Insertamos un botón para Aceptar, cambiándole el nombre a "cbAceptar", el texto a "Aceptar" y damos a la propiedad Default el valor Verdadero.

Vamos con los eventos: para el botón Cancelar la función que debemos escribir es exactamente igual que en el caso anterior:Private Sub cbCancelar_Click() Unload MeEnd SubLo único que hace es cerrar el cuadro de diálogo al producirse el evento "Click" del botón Cancelar.La función para el botón Aceptar también es muy similar a la anterior:Private Sub cbAceptar_Click() Range("rngNombre").Value = tbNombre.Text Range("RngApellido").Value = tbApellido.Text Unload MeEnd SubEsta función se ejecuta también cuando se produce el evento Click del botón llamado cbAceptar. Antes de cerrar el cuadro de diálogo debemos guardar en las celdas de la

Page 21: Capítulo 1

hoja de cálculo los valores de los cuadros de texto. Para ello utilizamos un objeto Range (a estas alturas somos unos autenticos expertos en el objeto Range), y le asignamos a su propiedad Value el valor de la propiedad Text del objeto TextBox. Esta es la única novedad, la utilización de una propiedad de los objetos TextBox (tbNombre y tbApellido).Si ejecutamos ahora el cuadro de diálogo veremos que funciona perfectamente: si cambiamos los nombres en el UserForm y pulsamos Aceptar veremos que las celdas de la hoja de cálculo han cambiado y ahora contienen los nuevos nombres.Pero hay una pequeña opción que se nos ha escapado: si vamos directamente a la hoja de cálculo, cambiamos los nombres en sus celdas, y ejecutamos el Userform, veremos que los controles de edición no tienen ahora los nombres actualizados, ya que no recogen los cambios que hemos hecho nosotros directamente en la hoja de cálculo.Para eso vamos a utilizar también los eventos. En esta ocasión vamos a utilizar un evento del Userform (sí, los UserForms también tienen eventos). Se trata del evento Initialize, que se produce justo antes del que el UserForm aparezca en la pantalla. Ese es el momento para hacer cualquier cambio en el Userform, como poner un texto en un control, que es lo que queremos hacer.Por lo tanto, seleccionamos el UserForm, pulsamos con el botón derecho y luego la opción "Ver código" (también se puede hacer doble-click sobre el Userform) y en la persiana de la derecha seleccionaremos el evento Initialize. Excel creará en ese momento la cabecera de nuestra función:Private Sub UserForm_Initialize()

End SubAhora tenemos que escribir el código que queremos que se ejecute antes de que se muestre el Userform. Lo que queremos hacer es poner en los dos cuadros de texto (el de nombre y el de apellido) el contenido de las celdas que tienen esos datos. Para ello utilizaremos el siguiente código:Private Sub UserForm_Initialize() tbNombre.Text = Range("rngNombre").Value tbApellido.Text = Range("rngApellido").ValueEnd SubNo creo que tenga demasiada dificultad. Es lo mismo que hemos escrito para el botón Aceptar pero al revés, es decir, damos a los cuadros de texto del Userform el valor que tienen las celdas de la hoja de cálculo.Pues ya está, ahora sí que el cuadro de diálogo funciona perfectamente, tanto si hacemos los cambios en el UserForm (se actualizará la hoja de cálculo si pulsamos Aceptar) como si hacemos los cambios en la hoja de cálculo (se actualizará el UserForm antes de aparecer en pantalla, porque se habrá ocurrido un evento Initialize).Bueno, hasta aquí llega esta tercera entrega. Todavía nos queda mucho por ver sobre los cuadros de diálogo (o UserForms, o formularios, como prefieras), pero eso lo dejamos para la próxima entrega. Hasta entonces te toca practicar, y sobre todo recuerda que lo más importante es tener claros los conceptos importantes: objetos, propiedades, métodos y eventos.

Capítulo 4. Cuadros de diálogo (Userforms). Segunda parte.

Page 22: Capítulo 1

Seguimos con los UserForms y los controles. En esta entrega vamos a ampliar el diálogo sobre datos personales, añadiéndole más opciones, y vamos a crear dos nuevos userforms: uno para convertir de pesetas a euros y viceversa, y otro para hacer operaciones (sumar, restar...) sobre un rango seleccionado (algo parecido a lo que hicimos antes, pero más completo).

Todos los ejemplos de este capítulo están incluídos en este fichero:Excel4.xls(116kbs)

Primero vamos a volver a hacer un diálogo de "Datos Personales" como el de la entrega anterior, pero añadiendo algunas cosas. Partimos del userform de la entrega anterior, que tenía un cuadro de edición para el nombre y otro para el apellido, y los dos botones clásicos (Aceptar y Cancelar). Habíamos escrito el código necesario para que al abrirse el diálogo (evento Initialize del Userform) los cuadros de edición se llenen con el texto de las celdas de la hoja de cálculo, y también para que cuando el usuario pulse Aceptar (evento Click del botón) se copie el texto de los cuadros de edición a la hoja de cálculo. Para hacer estos traspasos entre la hoja de cálculo y el Userform habíamos escrito un par de líneas de código en los eventos indicados, pero vamos a ver que hay otro método para hacerlo: Todos los controles tienen la propiedad "ControlSource", que se utiliza para decirle al control cuál es la "fuente" de su información, que será una celda o un rango de una hoja de cálculo. Por ejemplo, en el cuadro de edición del Nombre podemos poner como ControlSource la celda de la hoja de cálculo en la que está ese dato. Como siempre, no vamos a utilizar referencias absolutas a celdas y rangos (p.ej. Hoja1!A5), sino que vamos a utilizar nombres de rango. Por ejemplo, vamos a la hoja de cálculo y damos a la celda "fuente" el nombre "rngNombre" (rng porque es un rango de una hoja de cálculo). Luego vamos al editor VBE, seleccionamos el control de edición Nombre y en su propiedad ControlSource escribimos el nombre del rango que queremos que sea su "fuente", en este caso "rngNombre".Ahora hacemos lo mismpo para el apellido: primero damos el nombre "rngApellido" a la celda de la hoja de cálculo y luego escribimos rngApellido en la propiedad ControlSource del control de edición de Apellido.Ahora tenemos que borrar el código que habíamos escrito para pasar la información de hoja de cálculo al Userform y viceversa. Mejor que borrarlo, lo que haremos será "comentarlo", utilizando una comilla simple ', que indica a Excel que todo lo que escribamos en esa línea detrás de la comilla son cosas nuestras y que las ignore (el texto "comentado" aparecerá en otro color, normalmente en verde). Aprovechando que explico lo de los comentarios, nunca está de más recordar la importancia que tiene añadir al código todos los comentarios que sean necesarios. Cuando estás escribiendo una rutina sabes perfectamente cómo funciona y qué es lo que hace, y todos pensamos que los comentarios son innecesarios, pero cuando tras algunas semanas tienes que volver a ver la rutina te encuentras con un montón de líneas que no sabes para qué sirven ni cómo lo hacen, y si no las has comentado tienes que "bucear" en ellas para averiguarlo.A lo que íbamos, estábamos borrando el código de los eventos Initialize del Userform y Click del botón Aceptar. Vamos al editor VBE, hacemos doble-click sobre el Userform y nos aparece la rutina Userform_Initialize(). Ponemos una comilla delante de las dos líneas que se encargan de copiar los datos de la hoja de cálculo al userform, y veremos que dichas líneas cambian de color, indicándonos que para Excel son comentarios y los va a ignorar. Ahora volvemos al Userform y hacemos doble-click

Page 23: Capítulo 1

en el botón Aceptar, y nos aparece la rutina btnAceptar_Click(). Volvemos a poner las comillas en las dos líneas de código que queremos quitar y ya está.Si probamos ahora el diálogo, veremos que la propieda ControlSource funciona, y que antes de mostrar el diálogo "lee" el contenido de la hoja de cálculo y lo pone en el Userform, y cuando pulsamos Aceptar copia el contenido de los controles del Userform en la hoja de cálculo.Sin embargo he detectado un problema con el uso de ControlSource. Si hacemos algún cambio en el Userform y luego pulsamos el botón de "Cancelar", los cambios que hemos hecho en los datos se actualizan en la hoja de cálculo, cuando no deberían actualizarse porque hemos pulsado Cancelar. En cambio, si hacemos algún cambio y pulsamos la tecla Escape los cambios no se actualizan en la hoja de cálculo. Es un poco raro. Creo que "se me escapa" algo, si alguien descubre por qué ocurre esto que me avise.Bueno, ahora vamos a añadir un control nuevo, que Excel llama "cuadro combinado" (el nombre en inglés es ComboBox), que es la típica persiana que estamos hartos de ver en cualquier diálogo, y permite al usuario escoger una opción entre varias que le presentamos. En este caso vamos a mostrar una persiana para el "Estado Civil", y las opciones que vamos a presentar son "soltero, casado, viudo y divorciado".

Las propiedades más importantes de un ComboBox son: List: un conjunto de cadenas de caracteres (strings) que representan a todos

los elementos de la lista. Para acceder a un elemento en concreto utilizamos MiComboBox.List( 3 ), que nos devolvería el cuarto elemento de la lista, ya que el primero tiene el número 0.

ListCount: el número de elementos que hay en la lista. Si utilizamos MiComboBox.List( MiComboBox.ListCount-1 ) obtendremos el último elemento de la lista.

ListIndex: el número del elemento seleccionado actualmente por el usuario. Para obtener el texto del elemento seleccionado utilizaríamos MiComboBox.List( MiComboBox.ListIndex ). Si hemos definido el control como "multiselección" (es decir, que el usuario pueda escoger más de un elemento), esta propiedad no se puede usar, pero por ahora no nos vamos a meter en esto.

Rowsource: es el rango del que queremos que el ComboBox lea los elementos. Podemos utilizar esta propiedad, o bien introducir nosotros mismos mediante código los elementos (utilizando el método AddItem).

ControlSource: la celda en la que el ComboBox lee y escribe el elemento seleccionado. Igual que con RowSource, podemos utilizar esta propiedad para que el ComboBox nos escriba en una celda el elemento seleccionado o podemos utilizar código para obtener el elemento seleccionado (utilizando ListIndex).

Style: identifica el tipo de ComboBox que queremos. Tiene dos valores posibles:

o fmStyleDropDownCombo: el usuario puede escoger uno de los valores de la lista o escribir otro distinto.

o fmStyleDropDownList: el usuario sólo puede escoger uno de los valores de la lista.

ControlTipText: esta propiedad se aplica a todos los controles, pero como todavía no la he explicado, la pongo aquí. Esta propiedad sirve para mostrar al usuario un pequeño texto de ayuda sobre el control cuando ponga el ratón sobre el mismo, el ya clásico cuadrito amarillo.

Una vez vistas las propiedades, vamos con los métodos del objeto ComboBox:

Page 24: Capítulo 1

AddItem: sirve para añadir un elemento a la lista. Su sintaxis es MiComboBox.AddItem( 'Mi texto', 3 ). El primer parámetro es el texto del elemento, y el segundo parámetro (que es opcional), es la posición dentro de la lista que queremos para el nuevo elemento. Si no utilizamos el segundo parámetro, nuestro nuevo elemento se añadirá al final de la lista.

RemoveItem: para borrar un elemento. Su sintaxis es MiComboBox.RemoveItem( 3 ), para borrar el elemento número 3.

Clear: borra todos los elementos de la lista. Como siempre, hay muchos más métodos y propiedades, que están bastante bien explicados en la ayuda de Excel.Vamos a colocar nuestro ComboBox en el Userform, y una vez colocado vamos a las propiedades. Primero vamos a establecer la propiedad Style como fmStyleDropDownList, para que el usuario sólo pueda escoger uno de los valores que le presentamos (es decir, que no le dejamos que se invente un nuevo estado civil). Ahora vamos a la hoja de cálculo y escribimos en una celda cualquiera "Soltero", debajo "Casado", debajo "Divorciado" y debajo "Viudo". Ahora vamos a dar un nombre a este rango, seleccionando las cuatro celdas y escribiendo en el "Cuadro de Nombres" (en la parte superior izquierda) el nombre "rngEstadoCivil". Ya que estamos vamos a seleccionar cualquier otra celda para que el ComboBox almacene el elemento seleccionado por el usuario, y le damos a esta celda el nombre "rngValorEstadoCivil".Ahora vamos otra vez al editor de Visual Basic (VBE), seleccionamos nuestro ComboBox, y en la propiedad RowSource escribimos "rngEstadoCivil". En la propiedad ControlSource escribimos "rngValorEstadoCivil".Como propina, vamos a poner en la propiedad ControlTipText el texto "Selecciona tu estado civil", que es lo que el usuario verá en un cuadrito amarillo cuando ponga el ratón sobre el ComboBox. Recuerda que esta propiedad la tienen todos los controles.Ya tenemos nuestro ComboBox, y si lo probamos veremos que funciona perfectamente. Recuerda que el ComboBox coge los valores del rango establecido en RowSource, y almacena el valor seleccionado por el usuario en la celda establecida en ControlSource.

Como ejercicio podemos hacer lo siguiente: borramos las propiedades ControlSource y RowSource, y hacemos que el control funcione igual pero encargándonos nosotros mismos de poner los valores en la lista y luego identificar la selección del usuario y poner su valor en la celda que queremos. Para ello tendremos que utilizar las propiedades List y ListIndex, y los métodos Clear y AddItem, poniendo el código en los eventos

Userform_Initialize() y btnAceptar_Click().Ahora que ya dominamos el ComboBox, una buena noticia: el control ListBox ("Cuadro de Lista" según la traducción de Excel) funciona prácticamente igual. El ComboBox es el control en el que sólo se ve una línea y pulsando un botón sale una "persiana" con las distintas opciones, y en cambio en el control ListBox se ve siempre la lista de opciones, no hay persiana. Aparte de esta diferencia "visual", los dos tipos de controles son prácticamente iguales.Vamos a por otro control, el SpinButton (Botón de número). Este botón se utiliza normalmente combinado con un Cuadro de edición: si pulsamos el SpinButton hacia arriba aumentamos el valor del cuadro de edición, y viceversa.Las propiedades más importantes del SpinButton son:

Value: el valor del SpinButton, un número. Min: el valor mínimo que puede tener el SpinButton. Max: el máximo. SmallChange: el incremento/decremento que sufrirá la variable Value cada

vez que el usuario pulse el SpinButton. Normalmente es 1, pero lo podemos cambiar.

Page 25: Capítulo 1

Vamos a utilizar el control SpinButton combinado con un cuadro de edición que vamos a utilizar para almacenar la edad. Primero ponemos un cuadro de edición, que llamaremos "editEdad" (ya sabes, cambiando la propiedad Name). En una hoja de cálculo daremos el nombre "rngEdad" a una celda, y utilizaremos esta celda para la propiedad ControlSource de nuestro control "editEdad".Ahora colocamos un control SpinButton. Normalmente se suelen colocar a la derecha del cuadro de edición al que van asociados. En el cuadro de propiedades vamos a poner a Min el valor 0 (edad mínima) y a Max el valor 150 (edad máxima). El nombre del control lo dejamos como está (SpinButton1).Ahora tenemos que jugar un poco con los eventos: cada vez que el usuario pulsa el SpinButton se produce el evento Change. Cada vez que se produzca este evento queremos cambiar el valor del cuadro de edición "editEdad". Hacemos doble-click en el SpinButton y aparece la ventana de código, en la que escribiremos:Private Sub SpinButton1_Change() editEdad.Text = SpinButton1.ValueEnd SubBastante sencillo, ¿no? Simplemente damos a la propiedad Text del objeto "editEdad" el valor del SpinButton.Ahora tenemos que hacer lo mismo pero "al revés". Si el usuario va directamente al cuadro de edición y escribe una edad, queremos que el valor del SpinButton se actualice, ya que tanto el cuadro de edición como el SpinButton tienen que tener el mismo valor. Para ello usamos el evento Change del objeto editEdad. Hacemos doble-click sobre él y en la ventana de código escribimos:Private Sub editEdad_Change() SpinButton1.Value = editEdad.ValueEnd SubPrácticamente igual que antes. El único cambio es que utilizamos la propiedad Value de editEdad en lugar de la propiedad Text, porque queremos el valor numérico, y no la cadena de caracteres. Si en el control de edición escribes alguna letra en lugar de un número verás que el Userform se detiene mostrándote un mensaje de error porque no puede calcular la propiedad Value de editEdad. En una aplicación "de verdad" deberíamos escribir algo de código para evitar estos errores, pero todavía no hemos visto el control de errores (ya llegaremos).Todavía nos queda un pequeño detalle respecto al SpinButton. Cuando el Userform se carga por primera vez, el control editEdad lee de la hoja de cálculo la edad (porque se lo hemos dicho en la propiedad ControlSource), pero el control SpinButton no está actualizado, tenemos que darle el mismo valor que tiene el control editEdad. Para ello usaremos el evento Initialize el Userform, que ya conocemos de sobra:Private Sub UserForm_Initialize() SpinButton1.Value = editEdad.ValueEnd SubEl código es el mismo que el utilizado en el evento editEdad_Change(). Si probamos ahora el diálogo veremos que la combinación editEdad + SpinButton1 funciona perfectamente (aparte de la detección de errores, que veremos más adelante).Ahora vamos con otros tipos de controles: las casillas de verificación (CheckBoxes en inglés), y los botones de opción (OptionButtons). Para utilizarlos vamos a suponer que queremos que el usuario nos indique si utiliza o no una hoja de cálculo, y en caso de que sí la utilice nos diga cuál es su preferida.Lo primero es preguntar si utiliza una hoja de cálculo, y para ello vamos a utilizar una casilla de verificación, que puede tener el valor verdadero o falso. Como siempre colocamos el control sobre el userform y le damos el nombre "cboxUtilizaHoja". En la propiedad ControlSource vamos a escribir "rngUtilizarHoja", que es el nombre que hemos dado a un rango de una hoja de cálculo (en el fichero de ejemplo es la celda C18 de la Hoja1). Y en la propiedad Caption escribimos el texto del control, algo así

Page 26: Capítulo 1

como "Utiliza hoja de cálculo". También podemos escribir algo en la propiedad ControlTipText.Además de todas esas propiedades que ya conocemos las propiedades importantes de un control de verificación o CheckBox son:

Value: el valor del control. Puede ser verdadero o falso. TripleState: puede ser verdadero o falso (esto último por defecto). Si le damos

el valor verdadero el control tiene tres estados: verdadero, falso y nada (cuando se pone gris). En algunas ocasiones puede ser útil pero normalmente lo dejaremos como falso.

Ahora vamos a ver cuál es la hoja de cálculo preferida del usuario. Para ello vamos a utilizar unos botones de opción, para darle la opción de elegir entre Excel, Lotus 1-2-3 u otra hoja de cálculo.Lo primero que tenemos que hacer es colocar un control marco (Frame en inglés). Estos controles sólo sirven para agrupar controles y para mejorar la presentación del userform. También tienen sus propiedades y eventos, pero casi nunca se utilizan.Bueno, colocamos un control Frame en el userform, y ahora vamos a poner dentro de él los tres botones de opción. Para poner un control dentro del marco lo que hay que hacer es seleccionar el marco y sin quitar la selección añadir el nuevo control. Vamos a hacer esto tres veces, y añadiremos tres botones de opción dentro del marco.Para guardar los valores de los botones de opción vamos a dar nombres a tres celdas de la hoja de cálculo (en el ejemplo E16, E17 y E18), a las que nombraremos "rngExcel", "rngLotus" y "rngOtros". Ahora vamos a los tres botones de opción que hemos puesto en el userform y en la propiedad ControlSource de cada uno de ellos escribimos una de los nombres que acabamos de crear. También convendría cambiar la propiedad Caption de cada uno de los botones para mostrar el texto adecuado.Las propiedades Value y TripleState de un botón de opción funcionan igual que en el control de verificación, y el resto de propiedades no son demasiado importantes.Si probamos ahora el userform debería funcionar perfectamente, excepto un pequeño detalle. Si el usuario nos dice que no utiliza ninguna hoja de cálculo, los botones de opción siguen preguntándole cuál es su hoja de cálculo preferida, lo que evidentemente no tiene ningún sentido. Lo que tenemos que hacer es desactivar los botones de opción: para desactivar cualquier control (no sólo los botones de opción) se utiliza la propiedad Enabled; si esta propiedad es verdadera, el control está activado, y si es falso el control estará desactivado (aparece en color gris), y el usuario no puede interactuar con él.Lo que nos queda ahora es saber cuándo ha cambiado de estado (verdadero, falso) la casilla de verificación cboxUtilizaHoja. Como siempre, lo hacemos con un evento, el evento Change del control de verificación, que se ejecuta cada vez que cambia el estado del control. Por lo tanto, en el evento Change tendremos que cambiar el estado (activado, desactivado) de los botones de opción. El código es:Private Sub cboxUtilizaHoja_Change() Frame2.Enabled = cboxUtilizaHoja.Value OptionButton1.Enabled = cboxUtilizaHoja.Value OptionButton2.Enabled = cboxUtilizaHoja.Value OptionButton3.Enabled = cboxUtilizaHoja.ValueEnd SubFíjate que damos a la propiedad Enabled de los botones de opción y el marco el valor de la propiedad Value del control de verificación. También podríamos haber escrito: If cboxUtilizaHoja.Value = True Then OptionButton1.Enabled = True ..... Else OptionButton1.Enabled = False ..... End If

Page 27: Capítulo 1

El resultado es el mismo, pero la primera opción es bastante más elegante.Un pequeño detalle. Cuando el userform se inicia también deberíamos activar/desactivar los botones según el valor de la casilla de verificación. Una solución rápida sería escribir dentro del evento Userform_Initialize (que ya conocemos) el mismo código que en cboxUtilizaHoja_Change, pero no es lo más adecuado porque estaríamos escribiendo el mismo código en dos sitios distintos, cosa que hay que evitar porque si luego tenemos que hacer algún cambio en el código tendremos que hacerlo en dos sitios.Lo mejor es llamar a cboxUtilizaHoja_Change() desde el evento Userform_Initialize(). La rutina cboxUtilizaHoja_Change es llamada cada vez que se produce el evento Change, pero nada nos impide llamarla por nuestra cuenta en cualquier otro momento, como por ejemplo cuando se inicia el userform. El evento Userform_Initialize quedará así:Private Sub UserForm_Initialize() cboxUtilizaHoja_Change SpinButton1.Value = editEdad.ValueEnd SubPues ya tenemos el userform de datos personales completo, y ya hemos aprendido a usar prácticamente todos los controles. La apariencia final del userform de datos personales es la siguiente.

Como ejercicio, vamos a hacer otro userform, en el que no vamos a utilizar ningún control nuevo pero sí vamos a ver un evento nuevo (KeyUp). Lo que vamos a hacer es un diálogo en el que el usuario pueda escribir una cifra en pesetas y automáticamente le diremos cuántos euros son. Y al revés, si escribe los euros calcularemos cuántas pesetas son.Pues vamos al VBE, creamos un userform, y ponemos en él dos controles de edición, que llamaremos editPesetas y editEuros, dos etiquetas al lado de cada control de edición, y un botón para cerrar el diálogo.

Page 28: Capítulo 1

Primero lo más fácil. En el botón de cerrar (al que cambiaremos el Caption para que ponga "Cerrar", y que llamaremos btnCerrar) tenemos que poner el código para cerrar el userform:Private Sub btnCerrar_Click() Unload MeEnd SubAhora vamos a los cuadros de edición. Lo que queremos hacer es que cada vez que el usuario pulse una tecla se actualice el otro cuadro de edición. Por ejemplo, si el usuario va a escribir 2500 pts, nosotros actualizaremos el cuadro de edición de euros cada vez que el usuario pulse una tecla, sin esperar a que termine. Para eso vamos a utilizar el evento KeyUp, que se produce cada vez que el usuario pulsa una tecla.Para escribir el código de este evento vamos a la ventana de código de nuestro userform, y en las persianas de la parte superior seleccionamos el control editPesetas y en la parte derecha el evento KeyUp. Excel nos habrá puesto la declaración de la rutina (con los parámetros adecuados, que en este caso no nos interesan y vamos a ignorar) y el "End Sub" correspondiente. Ahora sólo tenemos que poner lo del medio:Private Sub editPesetas_KeyUp(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer) If editPesetas.Text <> "" Then editEuros.Text = Format(editPesetas.Value / 168, "0.00") Else editEuros.Text = "" End IfEnd SubEl "If" lo utilizo como una pequeña forma de detección de errores, por si el cuadro de edición está vacío (de todas formas, se pueden producir muchos errores, como por ejemplo si el usuario introduce una letra en lugar de un número, pero no vamos a ponernos ahora a escribir código para detectar todos esos errores). El resto es bastante sencillo, se trata de poner en el cuadro editEuros el importe de editPesetas dividido por 168 (el valor en pesetas de un euro), y utilizando la función Format para que sólo presente dos decimales. (la función Format es muy sencilla de utilizar, si quieres más información consulta la ayuda).Podemos probar a ejecutar ahora el diálogo y veremos que cada vez que introduzcamos un carácter en el cuadro editPesetas se actualiza el cuadro editEuros.Ahora tenemos que hacer que cuando escribamos algo en editEuros se actualice editPesetas. El procedimiento es exactamente el mismo:Private Sub editEuros_KeyUp(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer) If editEuros.Text <> "" Then editPesetas.Text = Format(editEuros.Value * 168, "0.00") Else editPesetas.Text = "" End IfEnd SubIgual que antes, pero multiplicando por 168 en lugar de dividir.Hasta ahora, todos los botones que hemos utilizado en los userforms servían para cerrar el userform, con la diferencia de que solemos poner uno para Aceptar y otro para Cancelar. Pero también podemos poner en un userform un botón que realice cualquier otra acción pero no cierre el userform. Lo más típico es que este botón haga algún cambio sobre los controles del userform.En este caso, aprovechando nuestro conversor de euros, vamos a crear dos botones, uno al lado de cada cuadro de edición, que van a pegar en la celda activa de la hoja de cálculo el contenido del cuadro de edición asociado.

Page 29: Capítulo 1

Colocamos los dos botones, uno al lado de cada cuadro de edición, y les damos los nombres btnPegarPts y btnPegarEuros, y les ponemos como Caption algo como "Pegar". Ahora vamos al código:Private Sub btnPegarPts_Click() ActiveCell.Value = editPesetas.ValueEnd Sub

Private Sub btnPegarEuros_Click() ActiveCell.Value = editEuros.ValueEnd SubEl evento que utilizamos es el evento Click, que ya conocemos de sobra. Y el código tampoco tiene ninguna dificultad, simplemente es poner en ActiveCell el valor del control de edición, editPesetas o editEuros.Como verás, al pulsar estos botones se pega el contenido en la hoja de cálculo, pero no se cierra el userform. Si quisiéramos que después de hacer el pegado se cerrara el userform tendríamos que añadir el clásico "Unload Me" a las dos rutinas anteriores.Así nos ha quedado el userform del conversor de euros:

Y para terminar esta entrega, vamos a hacer un diálogo para hacer operaciones sobre un rango, como los que ya hemos hecho, pero más completo. El diálogo va a permitirnos cambiar el rango seleccionado, y luego nos permitirá seleccionar la operación aritmética que queremos hacer sobre el rango (sumar, restar, multiplicar, dividir) utilizando para ello unos botones de opción.En este diálogo vamos a utilizar un control nuevo, el RefEdit, que sirve para que el usuario pueda introducir una referencia (un rango). Puede hacerlo escribiendo la referencia absoluta o el nombre del rango (como si fuese un cuadro de edición), o pulsando en el botoncito que aparece a la derecha, que hace que desaparezca el userform y el usuario puede seleccionar el rango con el ratón o el teclado.Los controles que vamos a poner en este userform son:

Tipo de control Name Caption

RefEdit RefEdit1 N/A

TextBox tbValor N/A

Frame Frame1 Operación

OptionButton obSumar Sumar

OptionButton obRestar Restar

OptionButton obMultiplicar Multiplicar

OptionButton obDividir Dividir

CommandButton btnAceptar Aceptar

CommandButton btnCancelar CancelarEl resultado final será algo así:

Page 30: Capítulo 1

Lo único nuevo que tenemos que aprender es que el rango que el usuario ha introducido en el RefEdit se guarda en la propiedad Text. Pero Text es una cadena de caracteres, por lo que si queremos hacer referencia al rango deberemos usar Range(RefEdit1.Text).Vamos con el código:Private Sub UserForm_Initialize() obSumar.Value = True RefEdit1.Text = Selection.AddressEnd SubPrimero hacemos que la operación seleccionada por defecto sea sumar (alguna tiene que ser) y que en el RefEdit aparezca como rango la selección que tenía hecha el usuario antes de llamar al diálogo.Ahora los botones:Private Sub btnAceptar_Click() HacerOperacion Unload MeEnd Sub

Private Sub btnCancelar_Click() Unload MeEnd SubLa única diferencia entre los dos botones es que uno de ellos llama a la rutina HacerOperacion antes de cerrar el userform. La rutina HacerOperacion es la siguiente:Sub HacerOperacion() Dim r As Range Dim c As Object Dim i As Double Set r = Range(RefEdit1.Text) i = tbValor.Value For Each c In r.Cells If obSumar.Value = True Then c.Value = c.Value + i ElseIf obRestar.Value = True Then c.Value = c.Value - i ElseIf obMultiplicar.Value = True Then c.Value = c.Value * i

Page 31: Capítulo 1

ElseIf obDividir.Value = True Then c.Value = c.Value / i End If Next cEnd SubPrimero obtenemos el rango seleccionado y lo almacenamos en "r". Luego obtenemos el valor que hay que utilizar, que el usuario ha escrito en tbValor, y lo almacenamos en "i". Luego hacemos un bucle "For Each - Next", que ya conocemos, para repetir el mismo código para todas las celdas del rango. El "If" tan largo que utilizamos es bastante más sencillo de lo que parece: lo único que hace es comprobar cuál es el botón de opción activado (Value = True) y efectúa la operación asociada a ese botón.Y aquí termina la cuarta entrega del curso. Si tienes cualquier duda o comentario que hacer, no dudes en contactar conmigo. En la próxima entrega hablaremos de la creación de menús y barras de herramientas personalizadas.

Capítulo 5. Menús y barras de herramientas. En esta entrega vamos a tratar sobre la creación de menús y barras de herramientas personalizadas para nuestras hojas. En Visual Basic for Applications, las barras de menú y las barras de herramientas están representadas por el mismo objeto (CommandBar), y su funcionamiento es exactamente igual.

Todos los ejemplos de este capítulo están incluídos en este fichero:Excel5.xls(90kbs)

Antes de nada, vamos a intentar aclarar la nomenclatura que se utiliza en VBA para hacer referencia a cada una de las partes de un menu.

Page 32: Capítulo 1

El nombre del menu en sí mismo es CommandBar. Un CommandBar (barra de menú) representa a todo el menú, como por ejemplo el que aparece cuando estás en una hoja de cálculo. Si cambias a una hoja de gráfico verás que el menú cambia: se ha cambiado de barra de menú (CommandBar).Cada una de las opciones de la barra de menú se llama CommandBarPopUp (menú desplegable según la traducción de Microsoft). Por ejemplo, en el menú de una hoja de cálculo la opción "Archivo" es un menú desplegable o CommandBarPopUp. Dentro del menú desplegable, cada una de las opciones se llama ControlButton (opción de menú). Por ejemplo, "nuevo" y "Guardar" son opciones del menú desplegable "archivo" de la barra de menú de "Hoja de cálculo" de Excel.Para tener acceso a las barras de comandos (que pueden ser menús o barras de herramientas) utilizaremos la propiedad CommandBars, que devuelve el conjunto de barras de comandos de la aplicación. Cada una de las barras de comando será por tanto un objeto CommandBar.Por ejemplo, para ver los nombres de todas las barras de comando que existen escribiremos la siguiente rutina:Sub ListaBarrasComando() Dim h as Object Dim dst as Range

Set dst = Sheets("Hoja1").Range("A1") For Each h in CommandBars

dst.Value = h.Name Set dst = dst.Offset(1, 0)

Next hEnd SubDe esta forma obtendremos el nombre de todas las barras de comando. Recuerda que puede haber barras de comando que existan pero no estén activas, que no aparezcan en la pantalla.Como habrás podido deducir, la propiedad Name de un objeto CommandBar nos devuelve el nombre de la barra de comando.1. Crear una opción de menú. Lo primero que vamos a hacer es crear una opcion dentro de un menú desplegable. Por ejemplo, vamos a crear una opción llamada "Macedonia" dentro del menú "Edición".Antes que nada, declaramos las variables que vamos a utilizar: Dim cBar As Object Dim cBarPopUp As Object

Page 33: Capítulo 1

Dim cButton As ObjectLa primera variable (cBar) la utilizaremos para almacenar el menú de hoja de cálculo entero, la segunda (cBarPopUp) para obtener el menú de "Edición" dentro de cBar, y la tercera para crear nuestra opción (Macedonia) dentro del menú de Edición.Vamos a obtener el menú de hoja de cálculo. Si te fijas en el resultado de la rutina ListaBarrasComando que hemos creado antes, verás que una de las barras de comando se llama "Worksheet Menu Bar". Esta es la barra de comandos que está presente cuando estás en una hoja de cálculo. Hay otras barras, como por ejemplo "Chart Menu Bar", que es la que aparece cuando estás en una hoja de gráficos.Para utilizar la barra de comandos "Worksheet Menu Bar" haremos lo siguiente: Set cBar = CommandBars("Worksheet Menu Bar")Con esto hemos conseguido que nuestra variable, cBar, contenga la barra de comandos que nos interesa. Ahora queremos seleccionar una parte de ese barra de comandos: queremos el menú de Edición. Para ello utilizamos el siguiente código: Set cBarPopUp = cBar.Controls("Edición")Hemos utilizado la propiedad "Controls" del objeto CommandBar. Esta propiedad nos permite acceder a todos los submenús de una barra de comandos. El objeto devuelto es del tipo "CommandBarPopup". Reconozco que la terminología es un poco confusa, pero así lo ha hecho Microsoft.Ahora ya tenemos el menú de "Edición" en nuestra variable. Y lo que queremos hacer es añadir una opción dentro de ese menú. Para hacerlo utilizaremos deberemos acceder a la propiedad "Controls" de nuestro menú de Edición. Fíjate que antes hemos accedido a la propiedad Controls del objeto cBar, y ahora vamos a acceder a la propiedad Controls del objeto cBarPopUp. Pues bien, una vez que accedemos a la propiedad "Controls" del menú Edición (cBarPopUp), utilizamos el método Add para añadir una nueva opción del menú: Set cButton = cBarPopUp.Controls.Add(msoControlButton)Almacenamos en nuestra variable cButton el resultado, porque luego queremos hacerle unos cambios.El tipo de control que queremos añadir puede variar ( msoControlButton, msoControlEdit, msoControlDropdown, msoControlComboBox o msoControlPopup ), pero en nuestro caso queremos una opción de menú, y utilizamos msoControlButton.Nos queda hacer que nuestra opción de menú (o ControlButton), tenga el texto que nosotros queremos y haga lo que nosotros queremos. Para ello utilizaremos las propiedades del ControlButton:

Caption: es el texto que queremos que aparezca en la opción de menú. En nuestro caso, "&Macedonia". El carácter "&" se utiliza para indicar que la letra que le sigue (la "M" en este caso) queremos que apareza subrayada y funcione como tecla rápida una vez que esté abierto el menú.

OnAction: es el nombre de la rutina que queremos que se ejecute cuando el usuario seleccione esa opción. En este caso vamos a darle el valor "MiMacro", que será una pequeña rutina que simplemente avisará de que hemos seleccionado esa opción.

ShortcutText: el texto que aparece en la opción del menú, a la derecha. Normalmente se suele poner la tecla rápida para esa opción de menú. Cuidado, porque esta opción sólo sirve para escribir el texto, pero no hace que la tecla rápida funcione, eso tendrás que hacerlo tú por otro lado.

FaceID: es el número de la imagen que queremos que se asigne a nuestra opción de menú. La imagen aparece en la parte izquierda de la opción. Excel tiene un montón de imágenes para nuestras opciones, y se pueden seleccionar cambiando el ID. Para ver todas las imágenes disponibles y saber qué ID corresponde a cada imagen, lo mejor es hacer una pequeña rutina que muestre

Page 34: Capítulo 1

todas las imágenes. (eso te queda como ejercicio; si tienes alguna duda escríbeme).

BeginGroup: true o false, indica si queremos que antes de nuestra opción se ponga un "separador", una línea que separe un poco nuestra opción de la anterior.

Como siempre, hay muchas más propiedades, pero creo que hemos visto las más importantes. Vamos a ver nuestra rutina completa: Sub CrearOpcionMenu() Dim cBar As Object Dim cBarPopUp As Object Dim cButton As Object BorrarOpcionMenu Set cBar = CommandBars("Worksheet Menu Bar") Set cBarPopUp = cBar.Controls("Edición") Set cButton = cBarPopUp.Controls.Add(msoControlButton) With cButton .Caption = "&Macedonia" .OnAction = "MiMacro" .FaceId = 7 .ShortcutText = "Ctrl+Shift+M" .BeginGroup = True End With Call MsgBox("Se ha creado la opción 'Macedonia' en el menú 'Edición'", vbOKOnly, "Macedonia")End SubPara verla en acción abre el fichero de ejemplo, y utiliza el botón "Crear opción de menú".Si te fijas en la rutina CrearOpcionMenu, hemos incluido una llamada a la rutina BorrarOpcionMenu. Esta última se encarga de borrar la opción "Macedonia" del menú Edición en caso de que ya exista, y llamándola evitamos que aparezcan dos opciones "Macedonia". La rutina BorrarOpcionMenu es la siguiente:Sub BorrarOpcionMenu() Dim cBar As Object Dim cBarPopUp As Object Dim cc As Object Set cBar = CommandBars("Worksheet Menu Bar") Set cBarPopUp = cBar.Controls("Edición") For Each cc In cBarPopUp.Controls If cc.Caption = "&Macedonia" Then cc.Delete Next ccEnd SubAl igual que en la rutina CrearOpcionMenu, primero obtenemos la barra de comandos "Worksheet Menu Bar", despues la barra "Edición", y luego, utilizando la instrucción "For Each", pasamos por todos las opciones de menú, y borramos aquellas cuyo "Caption" sea "&Macedonia" (incluyendo el &). Para borrar la opción de menú utilizamos el método Delete.2. Crear un menú desplegable. Ahora vamos a crear un menú desplegable (como el menú Archivo, o Edición, de la hoja de cálculo de Excel). Como siempre, primero declaramos las variables que vamos a utilizar. Dim cBar As Object Dim cBarPopUp As Object Dim cButton As Object

Page 35: Capítulo 1

Luego vamos a obtener la barra de comandos de la hoja de cálculo: Set cBar = CommandBars("Worksheet Menu Bar")Para añadir un menú desplegable a dicha barra de comandos vamos a utilizar el método "Add" de la colección "Controls" de la barra de comandos: Set cBarPopUp = cBar.Controls.Add(Type:=msoControlPopup, Before:=10)El tipo de control que queremos añadir es un "msoControlPopup", para indicar que queremos un menú desplegable. cBarPopUp.Caption = "&Macedonia"Ahora tenemos en cBarPopUp un menú desplegable, igual que en el punto anterior teníamos el menú desplegable "Edición". Ahora tenemos que añadir opciones en dicho menú desplagable, igual que hemos hecho antes: Set cButton = cBarPopUp.Controls.Add(msoControlButton) With cButton .Caption = "&Macedonia 1" .OnAction = "MiMacro" End WithTambién podemos añadir un submenú dentro de alguna opción de nuestro menú, de una forma muy parecida. La rutina completa para crear un menú desplegable es la siguiente:Sub CrearMenuDesplegable() Dim cBar As Object Dim cBarPopUp As Object Dim cButton As Object Dim i, j As Integer BorrarMenuDesplegable Set cBar = CommandBars("Worksheet Menu Bar") Set cBarPopUp = cBar.Controls.Add(Type:=msoControlPopup, _ Before:=10) cBarPopUp.Caption = "&Macedonia" For i = 1 To 10 If i <> 5 Then Set cButton = cBarPopUp.Controls.Add(msoControlButton) With cButton .Caption = "&Macedonia " & i .OnAction = "MiMacro" If i Mod 3 = 0 Then .BeginGroup = True End With Else Set cButton = cBarPopUp.Controls.Add(msoControlPopup) cButton.Caption = "&Macedonia " & i For j = 1 To 5 With cButton.Controls.Add(msoControlButton) .Caption = "Submenú Macedonia " & j .OnAction = "MiMacro" If j Mod 3 = 0 Then .BeginGroup = True End With Next j End If Next i Call MsgBox("Se ha añadido la opción 'Macedonia' en el menú principal", _ vbOKOnly, "Macedonia")End Sub

Page 36: Capítulo 1

Para ver esta rutina en acción utiliza el botón "Crear menú desplegable" del fichero de ejemplo.3. Crear una barra de menú. Ahora vamos a crear una barra de menú completa, como la barra de menú "Worksheet Menu Bar". Lo primero, como siempre, es declarar las variables: Dim cBar As Object Dim cBarPopUp As Object Dim cButton As ObjectEn lugar de obtener la barra de menú "Worksheet Menu Bar" y luego trabajar con ella, ahora lo que vamos a hacer es crear nosotros mismos una barra de menú, utilizando el método "Add" de la colección "CommandBars". Set cBar = CommandBars.Add("Barra Macedonia", msoBarTop, True)

El primer argumento es el nombre de la barra de comandos que vamos a crear. El segundo argumento es la posición de la nueva barra de comandos, y puede ser uno de los siguientes valores:

msoBarLeft, msoBarRight, msoBarTop, msoBarBottom: izquierda, derecha, arriba o abajo.

msoBarFloating: queremos que la nueva barra de menú sea flotante.

msoBarPopUp: la nueva barra de menús será contextual, como las que salen cuando pulsamos el botón derecho.

El tercer argumento (verdadero o falso) indica si queremos que la nueva barra de menú reemplace a la barra de menús activa o no. Una vez que tenemos nuestra barra de menú utilizamos el código que hemos aprendido antes para crear los menús desplegables y sus opciones. La siguiente rutina crea una barra de menú y varios menús desplegables y opciones:Private Const NOMBREMENU = "Menú Macedonia"

Sub CrearBarraMenu() Dim cBar As Object Dim cBarPopUp As Object Dim cButton As Object Dim i, j As Integer BorrarBarraMenu Set cBar = CommandBars.Add(NOMBREMENU, msoBarTop, True) For j = 1 To 5 Set cBarPopUp = cBar.Controls.Add(Type:=msoControlPopup) cBarPopUp.Caption = "&Macedonia " & j For i = 1 To j + 2 Set cButton = cBarPopUp.Controls.Add(msoControlButton) With cButton .Caption = "&Macedonia " & i .OnAction = "MiMacro" If i Mod 3 = 0 Then .BeginGroup = True End With Next i Next j Call MsgBox("Se ha creado la barra de menú 'Macedonia'.", vbOKOnly, "Macedonia")End SubHemos utilizado la variable "NOMBREMENU" para dar el nombre a la barra de menú. Cuando se usa una cadena en más de un sitio del código es aconsejable sustituir la cadena por una variable, para evitar errores al escribir la cadena en varios sitios.

Page 37: Capítulo 1

Con la rutina anterior hemos creado la barra de menú, pero todavía no la podemos ver, porque hay que activarla, usando: CommandBars(NOMBREMENU).Visible = TrueComo al crear la barra hemos indicado (con el tercer argumento) que esta barra tiene que sustituir a la que esta activa, la barra activa desaparece y la nuestra aparece. Para volver a desactivar nuestra barra, utilizaremos: CommandBars(NOMBREMENU).Visible = FalseSi queremos borrar la barra de menu que hemos creado utilizaremos el metodo Delete: CommandBars(NOMBREMENU).DeleteEn el fichero excel5.xls tienes unos botones que sirven para crear, activar, desactivar y borrar una barra de menú.4. Crear una barra de herramientas: Como hemos visto al principio, en VBA las barras de menú y las barras de herramientas están representadas por el mismo objeto (CommandBar), y su funcionamiento es prácticamente igual.Crear una barra de herramientas es exactamente igual que crear una barra de menú: Set cBar = CommandBars.Add(NOMBREBARRA, msoBarFloating, False)En este caso hemos creado una barra "flotante", pero podíamos haber utilizado cualquiera de los otros parámetros que hemos visto antes. Ahora vamos a crear un botón de la barra de herramientas. La única diferencia entre crear un botón y crear un menú desplegable es el tipo de control, el parámetro del método Add. En este caso utilizaremos "msoControlButton": Set cButton = cBar.Controls.Add(msoControlButton) With cButton .Caption = "&Macedonia " & i .OnAction = "MiMacro" .FaceId = Int(Rnd * 1000) End WithEl código utilizado para crear, activar, desactivar y borrar una barra de herramientas es el mismo que para una barra de menús. De hecho no hay ninguna diferencia entre ellas, en Excel las dos son una barra de comandos (CommandBar). Además, también podemos mezclar botones y menús dentro de una barra de comandos: sólo hay que crear la barra y luego añadir controles tipo "msoControlPopup" para los menús y controles "msoControlButton" para los botones. Bueno, aquí termina la quinta entrega del curso de VBA para Excel. Si tienes cualquier duda o comentario no dudes en escribirme.