Macros y Lenguaje VBA Aprender A Programar Con Excel 3 Edicion 1
Macros y Lenguaje VBA Aprender A Programar Con Excel 3 Edicion 1
Capítulo 1: Introducción
A. Introducción 14
A. Introducción 18
C. La interfaz 20
1. Los módulos 21
2. Los cuadros de diálogo personalizados 23
3. Las barras de herramientas 25
A. Introducción 28
B. ¿Qué es un objeto? 28
1. Propiedad de un objeto 28
2. Método de un objeto 28
C. Regla de codificación 29
1. Asociación de objetos 30
2. Asociación de propiedades o de métodos 30
D. Ayuda en línea 31
G. Los procedimientos 34
H. Las funciones 34
A. Introducción 38
B. La Grabadora de macros 38
C. Primer ejercicio 41
G. Síntesis 51
A. Introducción 54
C. El método MsgBox 55
1. Vista de un mensaje personalizado 55
2. Ver el resultado de una variable 56
3. Personalizar el mensaje 56
F. El método InputBox 68
1. Presentación 69
2. Las ventajas de trabajar con tablas 70
A. Introducción 72
B. La instrucción If 72
1. Presentación 72
2. Ejemplo de aplicación 73
3. Explicación 74
4. Transformación del código 74
5. Abreviatura de escritura 75
6. Condición anidada 76
1. Presentación 77
2. Ejemplo de utilización 78
a. Test a un solo valor 78
b. Test en varios valores no contiguos 78
c. Test en valores contiguos 79
3. Reversibilidad 79
A. Introducción 88
Capítulo 8: Depuración
A. Presentación 106
A. Introducción 166
A. Introducción 198
A. Introducción 216
A. Introducción 230
A. Introducción 244
A. Introducción 272
A. Introducción 308
A. Introducción 322
I. Síntesis 339
A. Introducción 342
1. On Error 342
2. La instrucción Resume 342
3. La instrucción Resume Next 342
4. La instrucción Err 343
5. GoTo 343
6. GoTo 0 343
1. Ejemplo 1 343
2. Ejemplo 2 346
3. Ejemplo 3 346
Anexos
índice 359
Tras la descripción del entorno de trabajo utilizado para la creación de macros, descubrirá los conceptos básicos de la
programación con VBA a través de los objetos, de sus métodos y de sus propiedades; a continuación, realizará su primer
programa gracias a la Grabadora de macros y después abordaremos los elementos fundamentales de la programación
VBA que son las variables, las condiciones y los bucles, antes de aprender a «depurar» su programa para corregir los
errores de programación.
La siguiente parte aborda la noción de programación modular y presenta, a través de ejemplos concretos, las
principales funciones que puede insertar en un programa como la gestión de cadenas de caracteres, la gestión de fechas y
horas, las manipulaciones en los libros Excel y sus propiedades; también verá cómo recuperar y trabajar desde un
programa VBA con todos los tipos de archivos que tenga en los directorios de su ordenador.
Los desarrolladores más aguerridos podrán aprender a optimizar su programa, trabajar con tablas en la memoria, celdas
con nombre y también con aplicaciones externas (envío de mails, creación de archivos pdf, conexión a bases Access). Por
último, aprenderá a crear cuadros de diálogo personalizados, insertar controles (etiqueta, zona de texto, botón, etc.) y poder
desarrollar así aplicaciones profesionales y elaboradas.
Frédéric LE GUEN
Conferenciante y consultor en Sistemas de Información para empresas desde hace más de quince años,
Frédéric LE GUEN, reconocido Microsoft MVP (Most Valuable Professional) desde 2010, es también
el creador de la web francesa de formación www.excelexercice.com. Gracias a sus muchos trabajos en
empresas desarrolló varias aplicaciones con Excel; en este manual nos ofrece su experiencia a través de
abundantes y variados ejemplos elegidos por su valor pedagógico y práctico.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Introducción
El objetivo de este libro es enseñarle, mediante prácticas, cómo diseñar macros con Microsoft Excel. Una macro es el
nombre que se le da a los programas que se escriben en un entorno de Office (Excel, Word, Access, PowerPoint).
Estas le permiten reproducir tareas un gran número de veces y sin error.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
¿A quién va dirigido este libro?
Ya sea usted estudiante, comerciante, jefe de proyectos, gestor, asesor, o simplemente utilice Excel a diario para la
gestión de sus cuentas o de una asociación, habrá constatado que a menudo tiene que realizar las mismas tareas y le
gustaría mejorar sus conocimientos de Excel para automatizar esas tareas.
Aunque nunca haya creado un programa, ni siquiera haya visto una línea de código en su vida, los ejemplos
siguientes le mostrarán, paso a paso, cómo crear macros mediante el lenguaje VBA.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
¿Qué es una macro?
Una macro es un conjunto de líneas de código que contienen instrucciones. Excel interpretará estas instrucciones para
realizar diversas tareas: operaciones matemáticas, operaciones en hojas de cálculo, operaciones en archivos, etc. Estas
instrucciones siempre se interpretarán del mismo modo y, además, el trabajo se hará mucho más rápido que si tuviera
que volver a hacer la misma tarea varias veces.
El lenguaje empleado para codificar estas instrucciones es el VBA (Visual Basic for Applications). La ventaja principal de
este lenguaje es que es muy comprensible puesto que las instrucciones se escriben (casi) como si fuese lenguaje
corriente.
Desde Excel 2007, Microsoft distingue entre guardar un libro sin macro (.xlsx) y guardar un libro con macro (.xlsm). Un
libro que contiene macros y que se ha guardado en formato xlsx no conservará sus líneas de código. Al mismo tiempo es un
mecanismo de seguridad para comprobar la existencia de un programa en un libro y una obligación a la hora de guardarlo.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
¿Qué interés tiene hacer macros?
Diseñar una macro tiene muchas ventajas. En primer lugar, el programa hará y deshará las instrucciones siempre en el
mismo orden. Por lo tanto, una macro le garantiza la integridad de su trabajo. Además, un programa le hará ganar tiempo
a la hora de realizar sus tareas.
Imagine que tiene que trabajar en un archivo de un millar de datos. Para tratar este archivo manualmente, podría
necesitar tres o cuatro horas, mientras que si trabaja con una macro, bastarían tres o cuatro segundos para tratar los
datos.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Contenido del libro
Este libro está dividido en cuatro partes. La primera parte le presenta el entorno de trabajo empleado para el diseño de
macros. La segunda parte le explica los principios básicos de programación. En la tercera parte, encontrará las
principales funciones que tendrá que utilizar en su trabajo. Y en la cuarta parte, descubrirá las técnicas de
optimización que permiten mejorar la ejecución de sus programas así como las técnicas utilizadas para la creación de
cuadros de diálogo personalizados.
Sea cual sea la versión de Excel con la que trabaje, en el libro encontrará las respuestas a sus problemas. Desde Excel
2003, el lenguaje VBA ha evolucionado muy poco, no obstante le señalaremos las pocas diferencias entre las versiones.
Puede consultar este manual capítulo por capítulo, en función de sus necesidades, sin que tenga que respetar
necesariamente el índice de contenidos. Este libro es ante todo una ayuda para la creación de programas. Todos los
ejemplos presentados se pueden descargar gratuitamente desde la página Información.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Introducción
Para crear macros, no se trabaja con Excel sino con otro programa, el Editor Visual Basic, más comúnmente llamado
Visual Basic Editor o incluso VBE.
Como se muestra en la imagen anterior, Microsoft Excel y Visual Basic Editor son dos aplicaciones que aparecen por
separado en la barra de tareas de Windows. Sin embargo, aunque VBE sea una aplicación aparte, esta no puede iniciarse
si no es desde Excel .
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
¿Cómo iniciar Visual Basic Editor?
El proceso difiere según la versión de Excel empleada.
Para iniciar Visual Basic Editor, utilice el menú Herramientas Macro y haga clic en la opción Editor de
Visual Basic o pulse [Alt][F11].
En las nuevas versiones de Excel, las herramientas que permiten crear macros están ocultas por defecto.
Para visualizar la pestaña reservada a las herramientas de programación, haga clic en la pestaña Archivo y después
en el botón Opciones. Seleccione la categoría Personalizar cinta de opciones. En la zona Pestañas principales,
active Desarrollador y después acepte.
En esta nueva pestaña, haga clic en el icono Visual Basic para iniciar VBE.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
En todas las versiones de Excel, puede iniciar VBE pulsando las teclas [Alt][F11].
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
La interfaz
Al inicio, la aplicación Visual Basic aparece como en la captura de pantalla siguiente:
La interfaz está compuesta por el Explorador de proyectos (1), la ventana de propiedades (2) y la zona de trabajo
(3).
Si el Explorador de proyectos no está visible, es posible visualizarlo usando el menú Vista Explorador de proyectos (o el
método abreviado [Ctrl] R). De la misma manera, si no está visible la ventana de propiedades, es posible mostrarla
mediante el menú Vista Ventana de propiedades (método abreviado [F4] ).
Al inicio, la zona de trabajo está siempre vacía, pero vamos a añadir módulos o cuadros de diálogo (traducido por
Userform) para empezar a crear un programa.
1. Los módulos
Los módulos son el alma de la programación. Un módulo se presenta como una hoja en blanco en la que usted escribirá sus
líneas de código.
Para insertar un módulo, en el Explorador de proyectos, haga clic con el botón derecho del ratón en su proyecto (o
en su libro Excel) y seleccione el menú Insertar Módulo.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
También es posible insertar módulos mediante el menú Insertar Módulo o bien haciendo clic en la flecha situada a la
Ahora, la zona de trabajo contiene un módulo que se presenta como una hoja en blanco. Verá aparecer este módulo
en el Explorador de proyectos.
- 2-
Por defecto, su nombre genérico es "Módulo1, 2, 3, …"
Para darle otro nombre, como por ejemplo Primer_Programa, escriba el nombre en la ventana de
propiedades en lugar de la palabra Módulo 1.
Para insertar un cuadro de diálogo, en el Explorador de proyectos, haga clic con el botón derecho del ratón
en el documento y seleccione el menú Insertar UserForm (que es la traducción de cuadro de diálogo).
Para ordenar cada elemento (Hoja de cálculo, Módulo y Userform) en subdirectorios, basta con activar el icono
Alternar carpetas del Explorador de proyectos.
Al inicio, solo está visible la barra de herramientas Estándar, pero una gran parte de las funciones que usará con frecuencia no
están en esta barra de herramientas. Se pueden mostrar otras dos barras de herramientas. Aconsejamos que se añadan dos barras
de iconos adicionales: la barra Edición y la barra Depuración.
Para visualizar las barras de herramientas que faltan, coloque el puntero del ratón en una zona vacía (sin texto ni
icono) de la barra de herramientas y haga clic con el botón derecho del ratón para que aparezca el siguiente menú
contextual.
En este ejemplo, solo está marcada la opción Estándar.
Marque las dos primeras opciones para que aparezcan la barra de Depuración y la barra de Edición.
Si estas barras de herramientas se muestran como una barra flotante y quiere colocarlas en la parte
superior de la ventana de la aplicación, haga clic en la barra de título de la barra de herramientas y
deslícela hacia las otras barras de herramientas. Cuando suelte el botón del ratón, la barra de
herramientas se colocará en el mismo nivel que las demás barras de herramientas.
Es importante señalar que las barras agregadas de esta forma aparecerán de nuevo cada vez que se inicie el editor;
el editor conserva las opciones de vista.
Introducción
La ventaja de Visual Basic, con respecto a otros lenguajes de programación, es su simplicidad de comprensión para
cualquier neófito; es un lenguaje orientado a objetos.
¿Qué es un objeto?
En Visual Basic, un objeto corresponde a uno de los elementos de la aplicación Excel: un libro (Workbook), una hoja de
cálculo (Worksheet), una columna (Column), una fila (Row), un rango de celdas (Range), una celda (Cells), etc.
1. Propiedad de un objeto
l Para una celda, las propiedades pueden ser su valor, su color, su tamaño, su fuente de carácter, etc.
l Para una hoja, las propiedades pueden ser su nombre, su visibilidad (oculta o no), su color de pestaña, etc.
En el capítulo Depuración veremos de qué manera mostrar la lista de métodos y propiedades vinculadas a un
objeto.
2. Método de un objeto
Objet.oMétodo
Objet.oPropiedad
Para ayudarle a encontrar todas las propiedades relacionadas con un objeto, tras escribir un punto, aparecerá un menú
desplegable.
En ese menú, identificará las propiedades mediante el icono y los métodos mediante el icono .
Si después de escribir un punto no aparece el menú desplegable, puede hacerlo aparecer pulsando las teclas [Ctrl] [Espacio].
Un poco más adelante en este capítulo veremos de qué manera mostrar la ayuda en línea específica de un término de
lenguaje VBA.
1. Asociación de objetos
Por ejemplo, para expresar que quiere copiar (Método) desde la hoja 2 (Objeto), la celda B5 (Objeto), escribirá la línea
siguiente:
Sheets("Hoja2").Cells(5,2).Copy
También puede especificar el nombre del libro cuando su macro necesite trabajar en varios archivos de Excel.
Workbooks("libro1.xlsx").Sheets("Hoja1").Cells(4, 5) = _
Workbooks("libro2.xlsx").Sheets("Hoja1").Cells(1, 3)
Atención: respete el orden de los términos. Una celda está incluida en una hoja de cálculo. Por lo tanto debe escribir el objeto
Hoja antes que el objeto Celda. Las hojas de cálculo tienen extensiones .xlsm porque solo
las hojas de cálculo con esas extensiones guardan también el código VBA. Las hojas de cálculo xlsx están vacías de código VBA.
Del mismo modo, puede asociar a un objeto varias propiedades o métodos. Por ejemplo, si quiere contar el número de filas no
vacías desde la celda A1, puede escribir la instrucción siguiente:
Cells(1, 1).CurrentRegion.Rows.Count
Esta escritura puede traducirse del siguiente modo: a partir de la celda A1, seleccionamos el conjunto de celdas adyacentes
(tanto en filas como en columnas), después nos centramos en las filas que contamos.
Ayuda en línea
Ya hemos mencionado algunos términos importantes que permiten identificar celdas y filas. El cúmulo de términos,
propiedades y métodos puede llegar a confundirle, pero existe una manera muy simple de encontrar propiedades y
métodos vinculados a un objeto y es utilizando la ayuda en línea.
En su navegador aparecerá una ventana con el término seleccionado. Si la página web está vacía querrá decir que el término
seleccionado no existe o bien que la selección no es correcta.
Un truco para saber si los términos están correctamente escritos consiste en escribirlos siempre en
minúsculas. Si los términos forman parte de instrucciones reconocidas, VBE los pondrá siempre en
mayúsculas. Si las instrucciones permanecen en minúsculas, querrá decir que el lenguaje VBA no los
reconoce.
Codificación de las celdas y de los rangos de celdas
Todos sus programas van a utilizar, de una forma o de otra, el contenido de una celda o de un rango de celdas.
Llegados aquí es importante explicar cómo comunicar con una celda y/o una hoja mediante el código VBA.
1. La celda
Siempre hay que escribir la palabra en plural. El número de fila y el número de columna son obligatoriamente
valores numéricos enteros positivos.
Observe que el número de fila se escribe en primer lugar, al contrario que en las referencias de celdas de Excel, donde el
número de fila aparece tras la letra de la columna: A1, D3, F34, etc.
2. El rango de celdas
Range(referencia)
Un rango de celdas se traduce por la instrucción Range. Esta instrucción puede utilizarse de tres maneras
diferentes.
Range("A1:C5").Select Las referencia s de las celdas se escriben "literalmente" entre comillas. No se pueden
variar esas referencias, están congeladas.
[A1:C5].Select Aquí, reemplazamos la instrucción Range por unos corchetes, las referencias están
escritas sin comillas .
Range(Cells(1, 1), Cells(3, Esta escritura puede parecer más compleja, pero es el método que queremos destacar ,
5)).Select ya que con este cada componente de las referencias de celda puede
gestionarse por una variable, como veremos a continuación.
Cuando se nombra una celda o un rango de celdas, puede recordar sus nombres en lugar de dar las referencias de las celdas.
[IVA].Select
De este modo, incluso si desplaza esta celda a otro lugar de su hoja de cálculo, la instrucción no se modificará en su código. En el
capítulo Optimización, sección Las celdas con nombre y las tablas, veremos las ventajas de tratar de esta manera las celdas
importantes de nuestro programa.
Significado del signo =
El signo = debe considerarse como un puente. La información que está a la derecha del signo = se traslada hacia el
elemento que está a la izquierda.
Cells(1,1) = 15
Cells(1,1).Interior.Color = vbRed
También podemos invertir la escritura. Para conocer el código del color de la celda A1 y poner ese resultado en la celda
D1, vamos a escribir el código siguiente:
Cells(1,4) = Cells(1,1).Interior.Color
Cells(1,4).Interior.Color = Cells(1,1).Interior.Color
A continuación, si queremos efectuar un cálculo retomando el contenido de la celda A1 (que contiene el valor 7, por
ejemplo) para añadirle el valor 5 y que el resultado aparezca en B1, escribiremos la fórmula de la siguiente manera:
Cells(2, 1) = Cells(1, 1) + 5
También podemos usar la misma celda como valor para usar en el cálculo y como celda para almacenar el
resultado. De esta forma, si queremos usar el contenido de la celda A1, agregarle una unidad complementaria y
transcribir el resultado también en A1, escribiremos:
Cells(1, 1) = Cells(1, 1) + 1
La consecuencia de esta línea de código será que el valor en A1 se modificará cada vez que el programa lea la línea. Ahora
quizá le parezca algo extraño, pero cuando estudiemos las variables y los bucles, esta escritura nos permitirá avanzar de fila en
fila al ejecutar el programa.
Los procedimientos
Todas las líneas de código deben escribirse en uno o varios procedimientos.
Un procedimiento se caracteriza por la escritura de la instrucción Sub (diminutivo de Subroutine que significa
Procedimiento en español) y de la instrucción End Sub que concluye el procedimiento.
Sub Cambiar_el_color()
Su programa
End Sub
Para iniciar este programa, puede o bien pulsar la tecla [F5] o bien hacer clic en el icono .
For, Next,
Para nombrar un procedimiento, se admiten todos los términos salvo las palabras reservadas (como
While, Cells, Date, etc.). Las palabras reservadas son necesariamente palabras en inglés. Además, si nombra su
procedimiento con varias palabras, el único separador autorizado es _ (underscore o guión bajo). Los espacios y el guión
() están prohibido s ya que podrían impedir que el programa se ejecutara.
Si su proyecto se compone de varios procedimientos, (véase capítulo Estructura de un programa), cada procedimiento deberá
tener un nombre único.
Las funciones
Las funciones se diferencian de los procedimientos por el hecho de que estas devuelven un valor al final del
tratamiento. Son muy importantes para aislar acciones o test concretos. Por ejemplo, si queremos saber si un archivo existe
en un directorio, escribiremos una función personalizada que nos dirá si el archivo existe o no; la función devolverá Sí
o No (para ver todo el código de la función consulte el capítulo Trabajar con los archivos Encontrar un archivo en un
directorio).
Para escribir una función, hay que escribir el código entre las instrucciones Function y End Function.
Por ejemplo, vamos a crear una función personalizada que devolverá en una celda el nombre de su hoja activa.
Escribiremos esta función de la forma siguiente:
Function Nombre_Hoja()
Nombre_Hoja = ActiveSheet.Name
End Function
Aunque simple, este código muestra la diferencia fundamental existente entre una función y un procedimiento. En las
funciones, el nombre de la función (Nombre_Hoja) se utiliza a la vez como nombre de la función y como nombre para el
resultado del cálculo. Todas las funciones creadas pueden nombrarse en una hoja de cálculo.
Observará que su función Nombre_Hoja aparece en el menú desplegable con el mismo título que las funciones
integradas de Excel.
En una hoja de cálculo, las funciones se interpretan directamente sin que usted tenga que iniciar el programa (como para un
procedimiento).
Esta función se ha creado sin ningún parámetro, pero en el capítulo Estructura de un programa Parámetros de llamada
veremos cómo podemos transmitirle parámetros personalizados.
Introducción
Una vez vistos los principios básicos de la programación, podemos escribir nuestro primer programa. Para ello, vamos
a pedirle a Excel que nos ayude gracias a la Grabadora de macros.
La Grabadora de macros
Esta herramienta grabará todas las acciones realizadas con Excel: selección de una celda, de un grupo de celdas, dar formato,
etc.
Muy a menudo, tendrá que eliminar algo de código para guardar solo lo esencial.
Para iniciar la Grabadora, vaya al menú Herramientas Macro, y active la opción Grabar nueva macro.
Aparecerá un cuadro de diálogo que le pide que escoja un nombre para su macro.
Indique el nombre de la macro y haga clic en Aceptar.
A partir de ese momento , todas las acciones que realice se grabarán en el Visual Basic Editor.
Para detener la grabación, haga clic en el botón Detener grabación que aparece en una barra de
herramientas flotante.
En la esquina inferior izquierda de la ventana de Excel, en la barra de estado, verá al lado de la instrucción Listo, el
icono de la Grabadora de macros.
En la versión de Excel 2007, el icono solo puede verse si se ha activado la pestaña Desarrollador en la cinta de opciones. Para ver
la pestaña Desarrollador, remítase al capítulo El editor de Visual Basic Cómo iniciar Visual
Basic Editor.
Aparecerá un cuadro de diálogo que le pide que escoja un nombre para su macro.
Indique el nombre de la macro y haga clic en Aceptar.
A partir de ese momento , todas las acciones que realice se grabarán en el Visual Basic Editor.
Para detener la grabación, haga clic en el mismo sitio (el icono habrá cambiado de apariencia):
Primer ejercicio
Para nuestro primer programa, vamos a trabajar con el libro (Ejemplo 4C) que podrá descargar desde la página
Información.
El objetivo de nuestro trabajo es combinar los nombres de la columna A cuando estos sean idénticos para alcanzar el
resultado siguiente:
Como comprobará, el número de líneas que se van a combinar, varía. Por lo tanto, no es posible utilizar la herramienta
Copiar formato ya que esta herramienta respeta no solo el formato, sino también el número de líneas afectadas. Así que
debemos crear una macro para realizar esta tarea automáticamente.
En un primer momento, vamos a utilizar la Grabadora de macros para codificar la primera combinación de celda. Es importante
que respete los pasos siguientes para que pueda llegar exactamente al mismo código que el que figura a continuación.
Inicie la Grabadora.
celdas A2 a A5.
Abra el cuadro de diálogo Formato de celdas (Formato Celda en Excel 2003 o, en Excel 2007, 2010, 2013
y 2016, haga clic en el icono de cuadro de diálogo del grupo Alineación en la pestaña Inicio).
Vertical: Centrar.
Pulse Aceptar.
Aparecerá un mensaje de error que le indica que la combinación hará desaparecer valores, pero no le haga
caso: haga clic en Aceptar.
A continuación acceda a Visual Basic Editor: en el Módulo1 encontrará un programa similar a este:
Sub Macro1()
’
’ Macro1 by.................
’
Range("A2:A5").Select
With Selection
.HorizontalAlignment = xlLeft
.VerticalAlignment = xlCenter
.WrapText = False
.Orientation = 0
.AddIndent = False
.IndentLevel = 0
.ShrinkToFit = False
.ReadingOrder = xlContext
.MergeCells = True
End With
End Sub
La primera línea que se interpretará corresponde a la selección del rango de celdas A2 a A5:
Range("A2:A5").Select
Es uno de los principales defectos de la Grabadora de macros: cuando activa un cuadro de diálogo de Excel
(Formato de celdas, Configurar página, etc.) la Grabadora codifica todos los elementos de este cuadro de diálogo, aunque
no los haya modificado.
En nuestro ejemplo, como solo hemos cambiado tres parámetros en el cuadro de diálogo, solo podemos
conservar las siguientes líneas:
Sub Macro1()
Range("A2:A5").Select
With Selection
.HorizontalAlignment = xlLeft
.VerticalAlignment = xlCenter
.MergeCells = True
End With
End Sub
Ejecución del código
Ahora vamos a utilizar el código para dar formato a las demás celdas del libro.
¡No ve ningún cambio en su hoja de cálculo! De hecho, la primera línea de código indica que ha seleccionado las
celdas A2 a A5, el programa solo se aplicará en esta selección (debido a la instrucción With Selection).
Para que este programa se aplique a cualquier selección de celdas, debe eliminar la línea de código Range
("A2:A5").Select o, mejor incluso, ponerla como comentario precediéndola de un apóstrofo.
El código pasa a ser:
Sub Macro1()
’Range("A2:A5").Select
With Selection
.HorizontalAlignment = xlLeft
.VerticalAlignment = xlCenter
.MergeCells = True
End With
End Sub
su programa.
Para cada selección realizada, el programa combina las celdas y alinea el texto en las celdas combinadas. Cada vez
que lo ejecute, aparecerá un mensaje de alerta de la combinación. En el capítulo Trabajar en un libro Excel, verá cómo
evitar estos mensajes con la propiedad DisplayAlerts.
En el capítulo sobre los bucles veremos cómo automatizar el programa para combinar todas las celdas sin necesidad de
seleccionarlas previamente.
hoja. Vuelva a la
Hoja1.
libro.
Detenga la grabación.
Sub Macro1()
Sheets.Add
After:=ActiveSheet
Sheets("Hoja1").Select
Range("A1").Select
Selection.Copy
Range("B4").Select
ActiveSheet.Paste
Application.CutCopyMode =
False Selection.Copy
Sheets("Hoja2").Select
Range("C2").Select
ActiveSheet.Paste
Application.CutCopyMode =
False Selection.Font.Bold =
True
Selection.Font.Underline = xlUnderlineStyleSingle
With Selection.Interior
.Pattern = xlSolid
.PatternColorIndex = xlAutomatic
.Color = 65535
.TintAndShade = 0
.PatternTintAndShade = 0
End With
Sheets("Hoja1").Select
Range("A1").Select
Selection.ClearContents
End Sub
Observe que cada etapa (seleccionar, copiar, pegar, eliminar) se ha codificado en el orden especificado. Veamos a
continuación cómo reducir el código sin que el resultado varíe.
2. La instrucción Select
Un análisis rápido del código muestra que la instrucción Select está presente prácticamente en todas las líneas. Cuando
tenga una línea que termine por Select y el siguiente empiece por Selection, podrá eliminar los dos
términos y escribir una sola línea de código :
Range("A1")S.elect
Selection.Copy
Pasará a :
Range("A1").Copy
Al eliminar todas esas repeticiones en Select, limpiará el código y reducirá sensiblemente el número de líneas de código
generado por la Grabadora.
3. La instrucción Copy
Range("A1").Select
Selection.Copy
Range("B4").Select
ActiveSheet.Paste
Es posible escribir todas esas instrucciones en una sola línea de código. El método Copy posee una serie de opciones
entre las que se encuentra una llamada Destination. Con esta opción podrá copiar el contenido de una celda y pegarlo en otra
dentro de la misma instrucción.
Range("A1").Copy Destination:=Range("B4")
Como veremos en la siguiente sección, el método Copy puede reemplazarse muy bien por otro método, siempre y cuando solo
debamos copiar el contenido de una celda. Por el contrario, si lo que debemos copiar es un rango de
celdas Range("A1:C3"), deberá usarse el método Copy, que es sumamente sencillo de usar.
4. Transferencia de datos
Cuando tenga que copiar el contenido de una sola celda en otra, no será preciso usar el método Copy, bastará con
transferir el valor de una celda a la otra.
Range("B4") = Range("A1") ’Copia el contenido de A1 en B4
Cells(2, 4) = Cells(1, 1) ’Misma acción
Esto es también válido para copiar el contenido de celdas entre hojas de cálculo. En ese caso habrá que especificar el
nombre de las hojas en la instrucción:
Sheets("Hoja2").Range("C2") = Sheets("Hoja1").Range("B4")
Sheets("Hoja2").Cells(3, 2) = Sheets("Hoja1").Cells(2, 4)
Por muy curioso que parezca, la Grabadora de macros optimiza el código usando un bloque de datos With ... End
With. El principio de esta instrucción es aplicar varias propiedades o métodos a un mismo objeto (celda, hoja
de cálculo, etc.).
Todos los formatos dados a una celda se escriben en un bloque With ... End With. Para ganar una línea de
código, también aquí es posible remplazar el término Selection por la referencia de la celda a la que desea
aplicarse el formato:
WithSheets("Hoja2").Range("C2")
.Font.Bold = True
.Font.Underline = xlUnderlineStyleSingle
.Interior.Pattern = xlSolid
.Interior.Color = 65535
End With
O también
With Sheets("Hoja2").Range("C2")
.Font.Bold = True
.Font.Underline = xlUnderlineStyleSingle
With .Interior
.Pattern = xlSolid
.Color =
65535
End With
End With
6. El código optimizado
En definitiva, si aplicamos los diferentes métodos enumerados arriba, podremos escribir el código en pocas líneas:
Sub Macro1()
Sheets.Add After:=ActiveSheet
Sheets("Hoja1").Select
Range("B4") = Range("A1")
Sheets("Hoja2").Range("C2") = Sheets("Hoja1").Range("B4")
With Sheets("Hoja2").Range("C2")
.Font.Bold = True
.Font.Underline = xlUnderlineStyleSingle
.Interior.Pattern = xlSolid
.Interior.Color = 65535
End With
Sheets("Hoja1").Range("A1").ClearContents
End Sub
Escrito de esta forma, el código es más fácil de leer ya que una línea de código corresponde a una acción y la
ejecución se ve sensiblemente mejorada.
Síntesis
Utilizar la Grabadora de macros tiene ventajas, pero también inconvenientes:
Ventajas Inconvenientes
Permite recuperar el código de objetos, de propiedades, La Grabadora de macros escribe muchos código inútil.
de métodos, así como los parámetro s de formato Todas las referencias de celdas se graban
(color, bordes, orientación, casillas de formulario, etc.). "literalmente" (se transcriben con sus coordenadas, sin
posibilidad de cambiarlas).
Todas las acciones se escriben a medida que se van realizando,
sin posibilidad de repetició n (véase Los bucles).
Introducción
Como v i m o s en el capítulo Primer programa, la Grabadora de macros convierte cada una de las selecciones de celda, de
rango de celdas, en referencias fijas:
Range("A3:B5").S
elect
Range("C8").Selec
t
Columns("D").Sel
ect
Este tipo de escritura del código tiende a desaparece r ya que las referencias serán invariablemente las mismas. Es
decir, el interés de hacer un programa es aplicar una instrucción a un elemento (una celda, una hoja de cálculo, un
libro, un gráfico, etc.) y después reproducir esta instrucción en otros elementos.
Este es el motivo por el que no deben escribirse las referencias de una celda directamente en el código, sino que
deberá usarse una variable que, como su propio nombre indica, permitirá hacer variar las coordenadas de la celda.
¿Qué es una variable?
Las variables pueden verse como cajas en las que se almacenan una serie de informaciones: cifras, fechas, texto, etc.
Por supuesto que no se trata de una caja en el sentido literal, sino de un espacio reservado en la memoria del
ordenador. Como el ordenador administra este espacio en la memoria, la cuestión no está ahí. Lo que debemos
recordar es que creando una variable (una caja) con un nombre propio, el VBA sabrá siempre en qué caja deberá leer o
recuperar los datos. De hecho, bastará con declarar un nombre de variable y atribuirle un tipo de datos para que
Visual Basic se ocupe del resto.
Realmente no hay reglas para el nombre que le da a sus variables; puede escoger cualquier palabra con la condición de
que no sea una de las palabras reservadas (palabras clave) de VBA (como Sheets, Cells, Worksheets, Columns,
Rows, etc.).
Una variable puede estar compuesta por una o varias palabras, pero estas no deben estar separadas por un espacio
o por un guion (). El único carácter de separación autorizado es el guion bajo
(_).
Para lograr mayor eficacia en la gestión de las variables es preferible optar por nombres comprensibles (Núm_Fila,
Nombre_Libro, Nombre_Hoja, etc.), en lugar de elegir nombres compuestos de una sola letra (i, j, k, etc.).
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
El método MsgBox
El método MsgBox es una función importante para comprender programas en Visual Basic ya que permite mostrar en todo
momento mensajes personalizados. Pero MsgBox no solo muestra mensajes personalizados, sino que también
bloquea la ejecución del resto del código.
Sub Test_Vista()
MsgBox "Mensaje personalizado"
End Sub
Inicie la ejecución del programa pulsando la tecla [F5] o haciendo clic en el icono . El resultado de este
programa muestra el siguiente cuadro de diálogo:
Como podrá observar, la instrucción para mostrar un mensaje es muy sencilla, pero lo que es importante
comprender es que mientras no pulse el botón Aceptar, la ejecución del código permanece bloqueada en la línea
MsgBox.
Ahora podrá mostrar más de un mensaje personalizado y también reagrupar texto personalizado con el contenido de una
variable al mismo tiempo.
Todos los textos introducidos entre comillas aparecerán tal cual en el cuadro de diálogo, pero las variables no deben escribirse
nunca entre comillas. De hacerlo, el cuadro de diálogo mostraría el nombre usado en el programa para calificar la variable y no
su contenido.
Según el contenido de la variable (texto, número, fecha, etc.), la instrucción precedente mostrará a la vez el texto escrito entre
comillas y el contenido de la variable. Por ejemplo, podemos escribir los siguientes mensajes:
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
l Mi_Variable tiene como valor 25/12/2017
En el apartado siguiente veremos los diferentes tipos de variables que se pueden utilizar.
Fíjese en el símbolo & entre el texto entrecomillado y el nombre de la variable. En el capítulo Administrar las listas de
caracteres veremos con más detalle técnicas propias para cadenas de caracteres (hay muchísimas), pero de
momento sepa que el símbolo & permite vincular el texto personalizado con el contenido de una variable.
3. Personalizar el mensaje
Puede personalizar la configuración del cuadro de diálogo MsgBox, el título de la ventana, el número de botones, los
iconos, etc. De esta forma los usuarios tendrán la impresión de que el mensaje es propio del programa y no un mensaje de
Excel.
El método MsgBox, además del mensaje que se quiere comunicar, posee las siguientes opciones:
La opción Botón permite cambiar el nombre de los botones que aparecen (Cancelar, Sí, No, etc.) y también cambiar el
icono que aparece a la izquierda del cuadro de diálogo. Para ello, es necesario seleccionar una de las constantes que
aparecen después de escribir una coma tras el mensaje personalizado.
Si selecciona la constante vbYesNo, el cuadro de diálogo mostrará los botones Sí y No, pero el texto de la línea
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
será ligeramente distinto ya que hay que indicar que la respuesta del usuario (Sí o No) se incluirá en una variable.
Sub Macro1()
Dim LaRespuesta As Long
LaRespuesta = MsgBox("¿Estás contento?", vbYesNo)
End Sub
Más adelante, en el capítulo Las condiciones, estudiaremos cómo tratar las respuestas y cómo conocer el valor de la respuesta en el
capítulo Depuración.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 3-
Declaración de una variable
Visual Basic permite trabajar con variables sin declararlas. Sin embargo, un lenguaje informático cualquiera no
puede trabajar al mismo tiempo con datos numéricos y datos textuales. En efecto, si trata de agregar cifras y texto, su
programa se detendrá y se quedará colgado, es decir, el programa se detendrá por completo sin terminar el
tratamiento.
En todos los ejemplos que se muestran a continuación, las variables se declaran sistemáticamente.
Por otro lado, al declarar las variables, es muy fácil recordar sus nombres haciendo uso de la combinación de teclas
[Ctrl][Espacio] .
Basta con introducir los primeros caracteres del nombre de una variable declarada y usar el método abreviado [Ctrl] [Espacio] para
que el nombre de la variable se complete al instante.
Podrá hacer obligatoria la introducción de variables modificando una opción de la configuración de Visual Basic
Editor.
La adición de un nuevo módulo empezará sistemáticamente por la instrucción, que impone la declaración de todas las
variables, Option Explicit.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
2. Comprobación de las declaraciones
Cuando se encuentra en modo Explicit, es decir que declara todas variables, no podrá iniciar el programa si una sola
variable no ha sido declarada. El programa será incapaz de comprender de qué manera interpretar la información.
Esto podría parecer un obstáculo, pero existe una manera muy sencilla de comprobar que todas las variables han sido
declaradas antes de iniciar el programa. Bastará con activar el menú Depuración, y el submenú Compilar
VBAProject.
La herramienta recorrerá todo el proyecto (todos los procedimientos y funciones) y si detecta que alguna variable se usa sin
haber sido declarada, lo señala mediante un mensaje de error.
3. Tipo de variable
El Visual Basic le propone una docena de tipos de variables distintas para declarar sus variables (véase Anexos Tipos
de variables). Sin embargo, no necesitará utilizarlas todas ya que normalmente solo empleará cuatro o cinco.
En todos los ejemplos de este párrafo, se usará el mismo nombre para la variable ( Mi_Variable), pero el tipo de declaración
será diferente. De esta forma le resultará más fácil comprender que es el tipo de declaración de la variable lo que prima
sobre su nombre mismo. El nombre es solo un medio nemotécnico que le permitirá saber si una
variable contiene una dirección (por ejemplo Dirección_Cliente), un código postal (CP_Cliente) o un
número de fila (Num_Fila).
a. Declaración de texto
Cuando una variable contenga texto, tendrá que declararse obligatoriamente en String.
Sub Test_Variable()
Dim Mi_Variable As String
Mi_Variable = "Hola" ’La variable Mi_Variable vale
"Hola" MsgBox "Valor de la variable : " & Mi_Variable
’Vista Mi_Variable = 10 ’El programa convierte la cifra
10 en
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
texto "10" y ningún cálculo será posible con ese dato.
End Sub
Si trabaja con cadenas de caracteres de longitud fija, se puede especificar la longitud que se espera. Por ejemplo, si
tiene una variable para almacenar un código postal (longitud siempre igual a cinco caracteres), puede hacerlo de la
siguiente manera:
Sub Test_Variable()
Dim Mi_Variable * 5 As String
Mi_Variable = "12345" ’La variable Mi_Variable vale
"12345" MsgBox "Valor de la variable: " & Mi_Variable ’Vista
Mi_Variable = "1234567" ’La variable Mi_Variable vale
"12345" MsgBox "Valor de la variable: " & Mi_Variable ’Vista
Mi_Variable = "11" ’La variable Mi_Variable vale "11
"
’(3 vacíos después de la cadena de caracteres)
MsgBox "Valor de la variable: " & Mi_Variable ’Vista End Sub
Encontrará otro ejemplo de la aplicación de variables String con una longitud definida en el primer párrafo del
capítulo Administrar las listas de caracteres.
b. Declaración de números
En VBA, un número con decimales y un número entero son dos elementos diferentes, y por lo tanto, no se declaran del
mismo modo. Para los números decimales, debe declararlos en Double y para los números enteros, ha de declararlos
en Long.
Sub Test_Variable()
Dim Mi_Variable As Long
Mi_Variable = "Hola" ’El programa se detiene porque el tipo transmitido
’ no es el que se esperaba.
Mi_Variable = 10 ’Mi_Variable vale 10
MsgBox "Valor de la variable: " & Mi_Variable ’Vista
Mi_Variable = 10,54 ’Mi_Variable vale 10 (no hay decimal en Long)
MsgBox "Valor de la variable: " & Mi_Variable ’Vista
End Sub
Si declara una variable en Long y le transmite un número decimal no se produce error, pero solo se conserva la parte entera.
Sub Test_Variable()
Dim Mi_Variable As Double
Mi_Variable = 20 ’Mi_Variable vale 20
MsgBox "Valor de la variable: " & Mi_Variable ’Vista
Mi_Variable = 20,88 ’Mi_Variable vale 20,88
MsgBox "Valor de la variable: " & Mi_Variable ’Vista
End Sub
Existen otros tipos de declaración de los números como Integer, Byte, Single, etc. Hace ya unos veinte años, era muy
importante la optimización de la memoria y, por tanto, declarar muy bien las variables. Hoy en día, dado el rendimiento de los
ordenadores ya no es necesario tener eso en cuenta.
El Visual Basic 7 (que salió con Office 2010) convierte sistemáticamente las declaraciones de tipo Byte, Integer
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 3-
en tipo Long y Single en Double al ejecutar un programa.
Por lo tanto, para los números trabaje únicamente con los tipos Double para los decimales y
Long para los enteros.
Desde que salió Office 2010, el Visual Basic trabaja con ordenadores con una arquitectura de 64 bits. Si aumenta el
tamaño de la memoria, puede realizar cálculos en 8 bytes. Para definir una variable con 8 bytes, le tiene que
designar el tipo LongLong. Esto solo funciona para las versiones de Office de 64 bits. Veremos más
detalladamente este aspecto concreto de las variables de 64 bits en el capítulo Optimización El entorno de
64 bits.
c. Declaración fechas
Las fechas son números particulares porque las manipulaciones vinculadas a fechas son específicas (día, mes, año).
Si desea almacenar fechas dentro de variables, deberá declararlas como tipo Date (es lógico).
El tipo de declaración Date se hace cargo tanto de fechas como de horas. Si envía un número entero a una
variable de tipo Date, el valor se convertirá en número de días desde el 01/01/1900 (primera fecha en Excel) y si
transmite un variable decimal, la parte entera se convertirá en fecha y la parte decimal en hora.
d. Declaración de objetos
El término objetos puede resultar confuso, pero hay que comprender que una hoja de cálculo, un libro, una
columna, una celda, etc. son, de hecho, objetos y varias propiedades están vinculadas a ellos.
En la imagen siguiente, por ejemplo, puede ver una parte de las propiedades vinculadas al objeto Hoja de cálculo. En el
capítulo Depuración veremos cómo hacer que aparezca la lista de propiedades vinculadas a objetos.
- 4- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Información obtenida gracias a las Inspecciones de la depuradora.
e. Declaración booleana
Las variables booleanas ( Boolean) solo aceptan dos valores: Verdadero o Falso. Son las variables más
elementales, ya que son las que ocupan menos memoria.
Este tipo de variables resulta muy útil para declarar el resultado de test como que:
l etc.
Cuando comprueba el valor de variables booleanas, puede comprobar que los valores sean Verdadero ( True) o
Falso ( False) o bien, todavía más simple 1 (True) o 0 (False).
Al contrario que las funciones booleanas que solo usan un bit, existe una declaración que usa todo el espacio en
memoria que VBA autoriza, es decir, 16 bytes. Esta variable se conoce como Variant y es posible almacenar en
ella cualquier tipo de datos (texto, números, fechas, booleanos) sin que el programa se interrumpa debido a
incompatibilidades en el tipo de datos.
De hecho, las variables en Variant pueden recibir múltiples tipos de datos durante de la ejecución del programa.
Resultan muy prácticas en el caso de declarar algunos tipos de tablas en memoria (vea el último apartado de este
capítulo) o para usar la función InputBox que permite transmitir datos en un programa (véase el párrafo
siguiente) ya que, una vez más, se desconoce el tipo de datos que introducirá el usuario. Pero el mayor riesgo de declarar todo
como Variant es realizar manipulaciones de variables (cálculo o concatenación) en los distintos
tipos. Por lo tanto, aprenda a usarlos bien pronto para evitar el abuso de este tipo de declaración.
Existen tres formas de declarar una variable, Dim, Static o Public. Según el tipo de declaración, la variable no
será "visible" por todo el programa.
a. La instrucción Dim
La instrucción Dim (diminutivo de Dimension) permite definir un nombre como si fuese una variable y asignarle un
espacio de almacenamiento.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 5-
DIM Nombre_de_la_variable AS Tipo de variable
Una variable se declara siempre al principio de un procedimiento. Al declarar una variable dentro de un
procedimiento, esta solo se reconocerá (o será visible) para este único procedimiento.
Una variable declarada en uno de los formatos numéricos tendrá como valor 0, una variable declarada de tipo
String estará vacía (no confundir con una cadena de caracteres que contiene espacios).
Esto implica que si vuelve a referirse a este procedimiento en el transcurso del programa, no conservará el último valor
almacenado en las variables como lo veremos en el capítulo Estructura de un programa.
En el capítulo Estructura de un programa, veremos que es posible escribir una variable Dim al principio de un
módulo.
b. La instrucción Static
La instrucción Static se declara también en un procedimiento pero, a diferencia de la instrucción Dim que
inicializa las variables desde la entrada a este procedimiento, una variable declarada en Static conserva su
valor en la memoria; este valor se conserva mientras Excel esté abierto. O dicho de otra forma, si vuelve a iniciar su
programa, su código se ejecutará utilizando el último valor de sus variables declaradas en Static.
Sub Variable_Static()
Static Núm_Fila as Long
Núm_Fila = Núm_Fila +1
Cells(Núm_Fila , 1) = Núm_Fila
End Sub
En el segundo paso, Núm_Fila sigue valiendo 1. Entonces, la instrucción Núm_Fila = Núm_Fila +1 colocará el valor de
la variable a 2, y por lo tanto en B1 el valor mostrado será 2. Y así sucesivamente al realizar las diferentes acciones de
este programa.
Observará que para cada nueva ejecución, el programa escribe el resultado en una nueva línea. Como la variable se ha
declarado en Static, cada nueva ejecución reutilizará el anterior valor calculado.
Si ahora utiliza el mismo programa pero con la variable declarada en Dim, el valor de la variable seguirá siendo igual a 1,
ya que Dim reinicializa sistemáticamente las variables.
Sub Variable_Static()
Dim Núm_Fila as Long
Núm_Fila = Núm_Fila +1
Cells(Núm_Fila , 1) = Núm_Fila
End Sub
- 6- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Debemos señalar que la instrucción Static casi nunca se usa en programación. Si desea conservar el contenido de una
variable durante toda la ejecución del programa, es preferible que declares las variables en Public.
c. La instrucción Public
Si desea que una variable sea visible en todos los módulos para todos los procedimientos de un proyecto (es decir,
en todos los Sub), deberá declararla al principio de un módul o y, sobre todo, no hacerlo en procedimientos
en modo Public de la siguiente forma:
Como para una variable Static, el valor se conservará en la memoria mientras Excel esté abierto y todos los
procedimientos o funciones de su proyecto reconocerán la variable.
Generalmente, los nombres de archivos, las rutas de acceso o los nombres de hoja de cálculo se
declaran en variable Public ya que esa información a menudo la vuelven a usar todos los
procedimientos.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 7-
Caso práctico de utilización de una variable
Queremos hacer un programa que mostrará un número de fila, sumar este número de fila a sí mismo y multiplicarlo
por sí mismo. Podemos escribir el código de la siguiente forma:
Sub Cálculo()
Cells(1, 1) = 1
Cells(1, 2) =+ 11
Cells(1, 3) = 1 * 1
End Sub
El resultado es el siguiente:
Si iniciamos varias veces este programa, obtendremos siempre el mismo resultado. Es lógico, ya que siempre
llamamos a los mismos valores.
Para hacer más dinámico este programa, vamos a reemplazar todos los valores 1 por una variable. El
Sub Cálculo()
Dim Val_Data As Long
Val_Data = 1
Cells(1, 1) V=al_Data
Cells(1, 2) V=al_Data + Val_Data
Cells(1, 3) V=al_Data * Val_Data
End Sub
Si iniciamos varias veces este programa, el resultado seguirá invariable ya que la ejecución se hará siempre con el valor
1.
Por descontado, cambiar a mano el valor de la variable es una herejía, pero en el capítulo Los bucles veremos cómo automatizar
la actualización del valor de nuestra variable. También podemos utilizar el método InputBox como
veremos en el siguiente párrafo.
La variable Val_Data también puede usarse como parámetro del número de fila en la instrucción Cells. El código
pasa a ser:
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Sub Cálculo()
Dim Val_Data As Long
Val_Data = 1
CellVsa(l_Data, 1) = Val_Data
CellVsa(l_Data, 2) = Val_Data + Val_Data
CellVsa(l_Data, 3) = Val_Data * Val_Data
End Sub
Inicie tres veces seguidas el programa con los valores para la variable Val_Data: 1, 2 y 3.
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
El método InputBox
En el ejemplo precedente, para cambiar el valor de la variable, no tenemos otra opción que modificar el programa
cambiando manualmente el valor de la variable Val_Data. Coincidirá con nosotros en que esa no es una solución
demasiado práctica.
Para evitar tener que cambiar a mano el valor de algunas variables en el programa, es posible transmitir el valor de una
variable en un programa en curso de ejecución. Esto puede hacerse gracias al método InputBox.
El método InputBox se construye en parte como el método MsgBox pero además, hay que prever una variable que
recibirá el valor que se quiere transmitir al programa.
Para continuar ejecutando el programa, deberá introducir alguna información (texto, número, fecha) en el cuadro de texto
y confirmar haciendo clic en el botón Aceptar.
En este ejemplo queremos recibir un número entero (Long) que corresponde al valor de la fila, pero para prevenir
cualquier error de tecleo, es preferible que declaremos la variable como Variant. Nuestro programa anterior puede
entonces escribirse:
En adelante, cada vez que se inicie el programa, un cuadro de diálogo le preguntará en qué fila desea que aparezca el resultado
y, una vez que pulse el botón Aceptar, Excel mostrará el resultado en la hoja de cálculo.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Las tablas en memoria
1. Presentación
En programación, puede designar a una sola variable varios valores ordenándolos unos tras otros mediante una
tabla.
Trabajar con tablas en memoria no es demasiado complicado; es exactamente como trabajar con informaciones
ordenadas dentro de una columna de su hoja de cálculo.
Suponiendo que tiene un programa que utiliza todos los días de la semana, en lugar de crear una variable para cada
día de la semana, puede crear una tabla que se llamará Día_Semana y que contendrá todos los días de la semana:
lunes, martes...
Para devolver los elementos ordenados en una tabla, basta con precisar la posición (el índice) en la tabla. Por
ejemplo:
Día_Semana(0) = Lunes
Llegados a este punto de nuestro manual, no es preciso abundar en más detalles sobre el trabajo con tablas en
memoria. Sepa, no obstante, que existen funciones propias de las tablas que hacen ganar muchísimo tiempo, tanto en lo
que se refiere a la escritura del código como a la ejecución del programa.
Por ejemplo, puede conocerse al instante el número de elementos ordenados en la tabla mediante la instrucción
UBound. Del mismo modo, si desea borrar todos los valores de una tabla en memoria, bastará con usar la
instrucción Erase.
Encontrará numerosos ejemplos de aplicaciones e instrucciones propias de las tablas en el capítulo Optimización, dentro de la
sección Las tablas en memoria.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Introducción
Un programa informático lleva a cabo tests constantemente: qué valor es mayor, qué celdas están vacías, etc. En
función del resultado obtenido, el programa efectúa o no un tratamiento específico.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
La instrucción If
IF condición THEN
[Instrucciones siVerdadero]
[ELSE]
[Instrucciones siFalso]
END IF
1. Presentación
La instrucción IF es muy simple de entender. Se realiza un test (o condición) que sea o bien verificado (Verdadero) o bien
no verificado (Falso).
l ...
Una condición solo devuelve dos datos: el test es Verdadero o Falso (y nada más).
En el caso de que el test sea Verdadero, el programa ejecuta las instrucciones que se encuentran después de THEN
(traducción de Entonces).
Si el resultado de la condición es Falso, el programa realiza las instrucciones que se encuentran después de ELSE
(traducción de Si no).
Caso concreto: si desea comprobar que una variable tiene el valor True, no es necesario que lo especifique en el test.
If Mi_Variable Then
En el capítulo Las funciones básicas veremos cómo integrar operadores de comparación u operadores lógicos (And,
Or) para enriquecer nuestros tests.
2. Ejemplo de aplicación
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
La siguiente hoja de cálculo muestra el resultado de los encuentros entre 6 equipos. En la columna A aparece el
nombre de los equipos, en la B el número de puntos en la clasificación y en la C, el resultado de la última jornada
(ganado = 1, perdido = 0).
Cuando se ha ganado un partido, el equipo se apunta 3 puntos, si no , el equipo se apunta 1 punto. Queremos añadir
+3 al valor de la columna B cuando el resultado de la columna C sea igual a 1; cuando el valor sea igual a 0, añadiremos
+1.
Sub Resultado_Partido()
If Cells(2, 3) = 1 Then
Cells(2, 2) = Cells(2, 2) + 3
Else
Cells(2, 2) = Cells(2, 2) + 1
End If
End Sub
3. Explicación
La línea Cells(2, 2) = Cells(2, 2) + 3 debe retrasarse ya que la celda B2 se presenta dos veces para 2
utilizaciones diferentes .
La parte de la derecha del signo = utiliza el valor de la celda B2 en la operación. Es decir, 35 + 3. Aquí la celda B2 se lee y
su contenido se utiliza en un cálculo.
La parte de la izquierda del signo = indica dónde guardamos el resultado. Por lo tanto, reutilizamos la celda B2 que aquí se
utilizará como lugar de almacenamiento .
En resumen:
Para permitir a nuestro programa que se ejecute en todas las líneas, vamos a sustituir en cada instrucción Cells,
el índice de la fila por una variable.
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Sub Resultado_Partido()
Dim Núm_Fila as Long
Núm_Fila = 2
If CellsN(úm_Fila , 3) = 1 Then
CellNsú(m_Fila , 2) = Cells(Núm_Fila , 2) + 3
Else
CellNsú(m_Fila , 2) = Cells(Núm_Fila , 2) + 1
End If
End Sub
Ahora, basta con que cambie el número de línea para aplicar este código a todos los equipos: Inicie
En el capítulo Los bucles veremos cómo hacer para que los valores de las variables se modifiquen automáticamente.
5. Abreviatura de escritura
Como la instrucción IF es una de las funciones más utilizadas en programación, existen otras formas de escribirla.
Retomando el mismo ejemplo, si el resultado es una derrota sin ningún punto, ya no necesitamos la instrucción
Else. Añadir 0 al resultado anterior obviamente no tiene sentido. Por lo tanto, nuestro test se escribiría:
If Cells(2, 3) = 1 Then
Cells(2, 3) = Cells(2, 3) + 3
End If
Pero en ese caso, también podríamos haber escrito toda la instrucción en una sola línea, colocando el resultado de la condición
justo después de la instrucción THEN:
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 3-
IF con Else también puede escribirse en una sola línea. En ese caso, hay que utilizar la instrucción
Una instrucción
lif que respeta la misma sintaxis que la función SI en Excel:
Sub Resultado_Partido()
Dim Núm_Fila as Long
Núm_Fila = 2
Cells(Núm_Fila , 2) =Iif(Cells(Núm_Fila , 3) = 1, _
Cells(Núm_Fila , 2) + 3, Cells(Núm_Fila , 2) + 1)
End Sub
6. Condición anidada
Como ya sabe, un partido puede ganarse o perderse, pero también puede haber un empate. Por tanto, debemos
modificar nuestra condición para tener en cuenta este tercer elemento.
Una función IF solo puede tratar dos resultados, Verdadero o Falso. Entonces, para integrar a nuestra condición IF
un tercer resultado, debemos crear otra instrucción IF en la parte Else de la primera condición. Es lo que se conoce
como imbricación de las condiciones (o Si imbricado).
En caso de partido empatado, un equipo gana dos puntos. La nueva tabla de resultados es la siguiente:
En lo que respecta al código, vamos a retomar el programa anterior y vamos a añadir una nueva condición. Vamos a reemplazar
el caso en que el test sea Falso, por un nuevo test en el que trataremos los dos últimos casos. El código será el siguiente:
Sub Resultado_Partido()
Dim Núm_Fila as Long
Núm_Fila = 2
If Cells(Núm_Fila , 3) = 1 Then
Cells(Núm_Fila , 2) = Cells(Núm_Fila , 2) + 3
Else
If Cells(Núm_Fila, 3) = 0 Then
- 4- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Cells(Núm_Fila , 2) = Cells(Núm_Fila , 2) + 1
Else
Cells(Núm_Fila , 2) = Cells(Núm_Fila , 2) + 2
End If
End If
End Sub
Como el número de casos que tratamos es importante, el número de funciones IF que combinamos entre sí,
también lo será y el programa corre el riesgo de ser ilegible para usted, y más aún para las personas que vayan a
leerlo. Si un caso así llega a producirse, es preferible optar por el método con la instrucción SELECT CASE.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 5-
La instrucción SELECT CASE
1. Presentación
A diferencia de la instrucción If que solo permite tratar dos casos (Verdadero o Falso), la instrucción Select Case
le permite precisar todos los valores posibles. Los diferentes casos que va a enumerar se llaman conexiones.
La conexión Case Else se escribe siempre al final de la instrucción y se efectúa cuando el valor que va a
comprobar no se encuentra en ninguna conexión anterior.
2. Ejemplo de utilización
Es el caso más simple. Puede crear una conexión para cada valor unitario posible.
Imaginemos que desea mostrar la cantidad de artículos que hay en ese momento en stock. En A1 puede ver el
nombre del artículo y desea que en B1 aparezca la cantidad en stock relativa a ese producto. Para ello
escribiremos el siguiente programa:
Sub Cantidad_en_stock ()
Select Case Cells(1, 1)
Case "Producto 1"
Cells(1, 2) = 25
Case "Producto 2"
Cells(1, 2) = 18
Case "Producto 3"
Cells(1, 2) = 36
Case "Producto 4"
Cells(1, 2) = 51
Case Else
Cells(1, 2) = "El producto no se conoce"
End Select
End Sub
En nuestro test, el contenido de la celda A1 se lee al principio de la instrucción y, según sea su valor, devolvemos la cantidad
en stock relativa a la conexión. Si el contenido de A1 es igual a Producto 3, la celda B1 mostrará 36 y así para todos los
productos.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Si el valor de A1 no se encuentra en las diferentes conexiones, como por ejemplo ’Producto 10’, la que se ejecute será
la instrucción Case Else.
En un Select Casetambién puede especificar en una misma conexión, todos los valores no contiguos posibles que
puede tomar el valor verificado. Para ello, basta con separar cada uno de ellos con una coma .
Por ejemplo, quiere crear un test que muestre la palabra "Número primo" en B1 en función del valor contenido en
A1.
Sub Es_Primo()
Select Case Cells(1, 1)
Case 1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37,
Cells(1, 2) = "Número primo"
Case Else
Cells(1, 2) = "No es un número primo"
End Select
End Sub
Puede indicar que una conexión Case debe ejecutarse para todos los valores comprendidos en un intervalo
mediante la instrucción To. Por ejemplo, si realiza un test que devuelva la calificación en función del valor
contenido en A1. Su test se escribirá de la siguiente forma:
Sub Resultado_Examen()
Select Case Cells(1, 1)
Case T0o 4.99
Cells(1, 2) = "No aprobado"
Case T5o 5.99
Cells(1, 2) = "Aprobado"
Case T6o 6.99
Cells(1, 2) = "Aprobado. Bien"
Case T7o 8.99
Cells(1, 2) = "Aprobado. Notable"
Case Else
Cells(1, 2) = "Aprobado. Sobresaliente"
End Select
End Sub
Observe que las diferentes conexiones no se solapan. Sin embargo, si se diese el caso, el programa no habría detectado la
anomalía y habría devuelto el primer caso respondiendo al criterio de selección.
3. Reversibilidad
Hasta ahora, hemos realizado tests en el valor de una celda o de una variable. Pero a la inversa también es posible. La
instrucción Select Casepermite verificar un valor y encontrar en qué caso se ha verificado ese test.
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Queremos aplicar un porcentaje de descuento en función del estado civil de un individuo. Para
Vamos a utilizar la instrucción Select Casepara verificar que una celda es igual a 1 o bien Verdadero (True).
Function Estado_Civil
Select Case True
Case Cells(1, 2)
Estado_Civil = 5
Case Cells(2, 2)
Estado_Civil = 0
Case Cells(3, 2)
Estado_Civil = 10
Case Cells(4, 2)
Estado_Civil = 15
Case Else
Es”tIamdposCiibvliel” =
End Select
End Function
Observe que en caso de que tenga que verificar el valor 1 o 0, también puede verificar en valores True (Verdadero)
o False (Falso).
Esta técnica de programación es muy útil para hacer tests en cuadros de diálogo y saber qué casillas de verificación
se han marcado y cuáles no.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 3-
¿IF o SELECT CASE?
Hace algunos años, la instrucción Select Casedesapareció de los programas ya que requería demasiada memoria. Después
cambiaron las cosas y el problema de la memoria se volvió obsoleto. Sin embargo, las ideas arraigadas son
difíciles de cambiar y la instrucción Select Caseno es muy popular entre los programadores.
Lejos de estas consideraciones, es más coherente utilizar la función IF cuando solo hay una, dos o incluso tres
posibilidades. A partir de ahí, es preferible utilizar la función Select Case.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Ejemplo de uso de dos instrucciones
Tomemos el siguiente ejemplo donde queremos extraer datos de una hoja de cálculo para copiarlos en otra. Sabemos que
este trabajo puede hacerse a través la herramienta Filtro de Excel, sin embargo, si debemos llevar a cabo la operación a
menudo, el hecho de crear un programa nos hará ganar mucho tiempo. Para ello escribiremos un test que
usará la instrucción IF y la instrucción Select Case.
Desea crear un programa que extraerá una serie de información a partir de un rango de datos y quiere que los
propios usuarios escojan ellos mismos la columna de filtrado y el valor que desean filtrar.
En tales casos, muchos desarrolladores de Excel usarían la Grabadora de macros para recuperar el código generado por
Excel. Esta solución funciona, por supuesto, pero genera un bloqueo porque obliga a conservar en el código el valor de la
columna que queremos filtrar, el criterio de filtrado (mayor, menor, diferente, etc.) y el valor a partir del cual se hará el
filtro.
Ahora bien, lo que nosotros queremos es que el usuario pueda elegir libremente esos tres elementos: la columna a filtrar,
el criterio de filtrado y el valor para realizar el filtro.
Supongamos que tenemos el siguiente documento, en el que hay fechas, nombres de los clientes, artículos,
cantidades y valores. Podrá descargar este ejemplo, llamado Ejemplo 6E1.xlsx, desde la página Información.
Para que los usuarios seleccionen los parámetros de filtrado, crearemos en tres celdas los parámetros para la
selección de la columna, el criterio de filtrado y el valor que deseamos probar.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Para crear un menú desplegable con las elecciones autorizadas, haga clic en la pestaña Datos grupo
Herramientas de datos Validación de los datos. Seleccione la opción Lista y a continuación, en la zona
Origen, introduzca los parámetros permitidos.
El principio del programa es muy simple, basta con reunir e introducir en variables los valores introducidos por el
usuario.
No obstante, y esto es específico de Excel, es preciso convertir las letras introducidas por el usuario en valores
numéricos. Esto puede hacerse muy fácilmente con esta línea de código:
A continuación, debemos escribir todos los casos posibles con ayuda de la función SELECT CASE.
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Test1 = Cells(Num_ Fila, Num_Columna) <> Val_Filter
Case "Contiene"
Test1 = Cells(Num_ Fila, Num_Columna) Like "*" &
Val_Filter &
"*"
Case "No contiene"
Test1 = Not (Cells(Num_ Fila, Num_Columna) Like "*"
& Val_Filter & "*")
End Select
El programa lleva a cabo una búsqueda mediante la instrucción Select Case, a partir del signo introducido por el
usuario (Val_Sign). Según el valor introducido por el usuario, buscaremos la escritura del test correspondiente y la
almacenaremos en la variable Test1. Como esta variable solo puede autorizar dos únicos valores (Verdadero o
Falso), deberemos declararla como booleano (Dim Test1 As Boolean).
Independientemente del signo seleccionado por el usuario, nosotros compararemos los dos mismos elementos:
l La celda en que se basa el test Cells(Num_Fila, Num_Columna), donde Num_Fila corresponde a la fila tratada y
Num_Columna corresponde a la columna introducida en los parámetros.
Al concluir este primer bloque de líneas de código que nos ha permitido traducir el test del usuario en lenguaje VBA,
deberemos usar el test para seleccionar o no los datos. El test se escribe de la siguiente manera:
If Test1 Then
Instruction
End if
Donde Instruction corresponde a las instrucciones de extracción que va a ejecutar. Podrá encontrar este ejemplo
en el archivo Ejemplo 6E2.xlsm.
No es necesario escribir Test1 = True ya que en las funciones If, el valor True se busca por defecto.
4. Programa completo
Para terminar el programa, solo quedará repetir este test tantas veces como filas haya en la hoja de cálculo. Es lo que se
conoce como hacer un bucle. Estudiaremos la administración de los bucles en el capítulo Los bucles.
Para comprender cómo funciona este programa, cambie los parámetros de filtrado escribiendo, por ejemplo:
C No contiene Santo
C Contiene Castelblanco
B = Paul
A >= 01/04/2014
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 3-
D <= 75
- 4- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Introducción
Los programas que hemos realizado hasta ahora solo pueden ejecutarse una vez con un único valor para las
variables. Para evitar tener que iniciar varias veces el mismo programa cambiando manualmente los valores de las
variables, vamos a estudiar ahora los bucles, que se encargarán de cambiar el valor de las variables en nuestro lugar
y de ejecutar así las instrucciones varias veces.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
La instrucción For ... Next
Con:
l Paso: incremento del valor del bucle. Este valor es facultativo; por defecto, el valor del Paso es igual a 1.
Un bucle FOR ... NEXT se comprende muy fácilmente: el bucle empieza con el valor Principio y se termina cuando el
Índice alcance el valor Fin. Los bucles FOR ... NEXT se utilizan para un número conocido de repeticiones .
A continuación, el programa interpretará las líneas de código correspondientes a su Instruction usando el valor de la
variable Index.
Por último, cada vez que se alcance la instrucción Next, la variable Index se incrementará. El incremento estará en
función del valor del Paso (si se omite el Paso, el incremento será de una unidad).
Todas las etapas del bloque Instruction se repetirán hasta que la variable Index alcance el valor límite definido por la
instrucción To.
Vamos a retomar el ejemplo del método InputBox realizado en el capítulo Las variables pero vamos a remplazar la
instrucción InputBox por un bucle para que el programa ejecute 10 veces los cálculos. El programa pasa a ser:
Sub Programa_Principal()
Dim Val_Data As Long
ForVal_Data = 1 To 10
Cells(Val_Data, 1) = Val_Data
Cells(Val_Data, 2) = Val_Data + Val_Data
Cells(Val_Data, 3) = Val_Data * Val_Data
NextVal_Data
End Sub
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
A continuación, el programa accede al bloque de instrucciones que se repetirá; la variable Val_Data se utiliza en los
parámetros de cálculo y para escribir el resultado. En nuestro primer pasaje, el resultado se inscribirá en la primera fila
de la hoja de cálculo. El programa escribirá en la celda A1 el valor 1, en A2, el resultado 1 + 1 es decir, 2 y en A3, el
resultado 1 * 1 es decir, 1.
A continuación, el programa llega a la instrucción Next que aumentará (o incrementará) la variable Val_Data en una
unidad. Al mismo tiempo, se realiza un test para verificar que la variable Val_Data no ha alcanzado el valor máximo
situado después de To, es decir, 10 en nuestro ejemplo. Como en este momento, Val_Data vale 2, el programa
volverá a la instrucción For. Y así sucesivamente, hasta que la variable Val_Data alcance el último valor del bucle, es
decir, 10.
Llegados aquí podrá poner como valor máximo del bucle un valor diferente de 10. Reinicie el programa cambiando el valor
máximo para que el nuevo resultado aparezca en la hoja de cálculo.
A título de ejemplo, ponga 1000 como valor máximo y observe cuánto tiempo emplea su ordenador en hacer los cálculos.
Hasta ahora, hemos utilizado una sola variable para modificar la referencia de las filas de una celda. Pero como ya sabe, la
instrucción Cells se compone de la referencia de una fila y de una columna. También es posible crear un
programa que haga variar el índice de las filas y el índice de las columnas.
En el ejemplo siguiente vamos a crear una tabla de multiplicación 15x15. Y para que entienda bien la lógica de la construcción
del programa, vamos a desgranar cada etapa.
a. Etapa nº 1
Para su primer programa, no trate de diseñar el problema entero. Empiece siempre su programa calculando una sola celda . A
continuación, agregue los bucles y variables que permitan reproducir este cálculo en las demás celdas de la hoja.
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Sub Tabla_Multiplicación()
Cells(1, 1) = 1 * 1
End Sub
b. Etapa nº 2
Ahora introduzca el primer bucle que permita el incremento de filas. Reemplazaremos el índice de las filas por una
variable que servirá también en nuestro cálculo. El código pasa a ser:
Sub Tabla_Multiplicación()
Dim Núm_Fila as Long
ForNúm_Fila = 1 To 15
CellNsú(m_Fila, 1) = Núm_Fila * 1
Next
End Sub
Este programa completará las quince primeras filas de la columna A dando los valores de 1x1 a 15x1.
c. Etapa nº 3
Para finalizar, vamos a construir un segundo bucle que permita hacer variar el índice de las columnas:
Sub Tabla_Multiplicación()
Dim Núm_Fila as Long
Dim Núm_Col as Long
ForNúm_Col = 1 To 15
For Núm_Fila = 1 To 15
Cells(Núm_FilNaú,m_Col) = Núm_Fila * Núm_Col
Next
Next
End Sub
d. Síntesis
El encadenamiento de tareas es muy sencillo. El programa ejecuta, en primer lugar, el bucle de las columnas y
después, el de las filas que se realiza quince veces.
Cuando termina el bucle de las filas, incrementamos en una unidad la variable de las columnas para rellenar la columna B.
Y después, volvemos a empezar el bucle de las filas partiendo del valor 1 (iniciando siempre la variable al principio del bucle).
Esta vez los resultados se introducirán en la columna B (ya que el índice de la columna vale
2) para los valores que van de 2x1 a 2x15. Y así sucesivamente, hasta que el bucle de las columnas llegue al
último valor, 15.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 3-
Bucle según condición
WHILE condición
[Instrucción]
WEND
a. Principio
A diferencia de un bucle FOR ... NEXT en el que se impone especificar el número de veces que se ejecutará el
bucle, un bucle WHILE ... WEND se para cuando se verifica un tes t (ver capítulo Las condiciones).
Por ejemplo, es posible realizar un bucle hasta que el programa alcance la primera celda conocida. Así, sea cual sea el
número de celdas no vacías de una columna, el bucle se detendrá cuando el programa alcance la primera celda vacía.
b. Ejemplo de aplicación
Vamos a escribir un programa que recorrerá todas las filas de la columna A hasta que lleguemos a la última celda. Por
cada celda no vacía, escribiremos el número de fila de la columna B.
Sub Programa_Principal()
Dim Fila_Leída As Long
While Cells(Fila_Leída, 1) <> ""
Cells(Núm_Fila, 2) = Núm_Fila
Wend
End Sub
c. Obligación
A diferencia de un bucle FOR ... NEXT, un bucle WHILE impone inicializar el primer valor de la variable e
incrementar la variabl e en el programa.
Sub Programa_Principal()
Dim Fila_Leída As Long
Fila_Leída = 2 ’Inicialización de la variable
While Cells(Fila_Leída, 1) <> ""
Cells(Fila_Leída, 2) = Fila_Leída
Fila_Leída = Fila_Leída + ’1Incremento
Wend
End Sub
Por desgracia, frecuentemente olvidamos incrementar la variable del bucle, y como consecuencia, se bloquea el programa.
Para salir de esta situación, pulse las teclas [Ctrl][Pausa] y podrá volver a tener el control de su
programa.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
2. Ejemplo de código
Vamos a retomar el ejemplo del capítulo Primer programa Primer ejercicio, que combina las celdas de un mismo
cliente a partir del archivo Ejemplo 4C. Recordemos que habíamos creado el siguiente código:
Sub Macro1()
With Selection
.HorizontalAlignment = xlLeft
.VerticalAlignment = xlCenter
.MergeCells = True
End With
End Sub
Para que este código se pueda utilizar en todo el documento, hay que seleccionar un rango de celdas antes de iniciar
el programa. Gracias a los bucles, vamos a adaptar este código para que funcione en todos los casos,
independientemente del número de filas que queramos combinar.
Para poder seleccionar el rango de celdas correspondiente a un mismo cliente, debemos crear un programa con dos variables:
l una primera variable correspondiente a la fila de principio del rango de celdas ( Núm_Fila).
l una segunda variable correspondiente al número de fila de fin del rango de celdas de la selección ( Fila_Fin).
La variable de los números de fila servirá, al mismo tiempo, para determinar la fila de partida de la combinación y para
encontrar la última fila de nuestros valores para detener el bucle.
l El primero para recorrer el conjunto de filas de la columna A (hasta que encontremos una fila vacía).
l El segundo se utilizará para encontrar la última fila del rango antes de cambiar el nombre del cliente.
El primer bucle es clásico. Hay que leer en secuencia las celdas de la columna A hasta que se encuentre una celda no
conocida y así, acabar el programa.
Sub Macro1()
Dim Núm_Fila As Long
Núm_Fila = 2
While Cells(Núm_Fila, 1) <> ""
INSTRUCCIONES
Núm_Fila = Fila_Fin + 1
Wend
End Sub
El segundo bucle determina el rango de celdas que será objeto de la combinación. Para ello, debemos realizar un
bucle que verifique la igualdad entre los nombres de dos celdas contiguas.
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
En una primera variable, guardaremos la primera fila en la que haya igualdad de nombres. Hacemos bucles en los
nombres tantas veces como haya nombres iguales y cuando detectemos dos nombres distintos, recuperamos el valor de
la última fila leída. Así, tendremos la primera y la última celda que corresponde a un mismo cliente.
Sub Macro1()
Dim Núm_Fila As Long
Núm_Fila = 2
’ Test sobre la celda vacía para detener el programa
While Cells(Núm_Fila, 1) <> ""
Fila_Fin = Núm_Fila
’ Test sobre la similitud del nombre de un cliente
While Cells(Fila_Fin, 1) = Cells(Fila_Fin + 1, 1)
Fila_Fin = Fila_Fin + 1
Wend
’INSTRUCCIONES DE FUSIÓN
Núm_Fila = Fila_Fin + 1
Wend
End Sub
Así, cuando ya no se verifica el test sobre la similitud de los nombres (y por tanto el test es Falso) tenemos en la
variable Núm_Fila el valor de la primera celda del rango y, en la variable Fila_Fin, el valor de la última celda del
rango.
El rango de datos que queremos fusionar se conoce, por tanto, solo nos faltaría copiar el código del formato
después de este segundo bucle.
Fila_Fin = Núm_Fila
’ Test sobre similitud de un nombre de cliente
While Cells(Fila_Fin, 1) = Cells(Fila_Fin + 1, 1)
Fila_Fin = Fila_Fin + 1
Wend
End Sub
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 3-
En este programa, no es posible gestionar los bucles con un FOR ... NEXT, ya que no conocemos de antemano el
número de filas que formarán parte del rango que vamos a combinar.
Para evitar la aparición del mensaje de alerta en el momento de la combinación, vamos a indicar a Excel que no debe
mostrar ningún mensaje durante la ejecución del programa. Ahora agregamos la instrucción
Application.DisplayAlerts = False al principio del programa y después, justo antes de dejar la macro, volvemos a
poner el parámetro en True para que Excel vuelva a mostrar los mensajes de error (cf. capítulo Trabajar en un libro
Excel El objeto Application).
Este es el código final que realiza las operaciones de combinación para todo el documento:
Sub Macro1()
Dim Núm_Fila As Long
Núm_Fila = 2
Application.DisplayAlerts = False
While Cells(Núm_Fila, 1) <>
"" Fila_Fin = Núm_Fila
While Cells(Fila_Fin, 1) = Cells(Fila_Fin + 1, 1)
Fila_Fin = Fila_Fin + 1
Wend
With Range(Cells(Núm_Fila, 1), Cells(Fila_Fin, 1))
.HorizontalAlignment = xlLeft
.VerticalAlignment = xlCenter
.MergeCells = True
End With
Núm_Fila = Fila_Fin + 1
Wend
Application.DisplayAlerts = True
End Sub
3. Do ... Loop
O:
DO
Instrucción
LOOP {while | Until} condición
a. Presentación
Los bucles DO ... LOOP son similares a los bucles WHILE ... WEND: hay que inicializar la variable utilizada por el bucle
antes de entrar en la celda y, a continuación, incrementar dicha variable dentro del bucle.
Es posible hacer el test con While (traducción de Mientras) pero también con Until (traducción de Hasta). Además,
es posible hacer un test al principio del bucle o al final de este.
- 4- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
b. Ejemplo de aplicación
El siguiente documento es una hoja de ausencias que se compone de dos columnas: la primera contiene las fechas
y la segunda, los nombres de los ausentes. El archivo correspondiente se llama Ejemplo 7C3b.
Como habrá comprobado, para la misma fecha, puede haber uno o varios nombres. Para mejorar la legibilidad de este
documento, quiere organizar su tabla presentando en la misma fila, una fecha y todos los nombres
correspondientes a esa fecha.
Sub Main()
Dim Núm_Fila As Long
Dim Col_Escritura As Long, Fil_Escritura As Long
Fil_Escritura = 1
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 5-
Núm_Fila = 1
While Cells(Núm_Fila, 1) <>
"" Col_Escritura = 5
Do
Cells(Fil_Escritura, 4) = Cells(Núm_Fila, 1)
Cells(Fil_Escritura, Col_Escritura) = Cells(Núm_Fila, 2)
Col_Escritura = Col_Escritura + 1
Núm_Fila = Núm_Fila + 1
Loop While Cells(Núm_Fil-a 1, 1) = Cells(Núm_Fila, 1)
Fil_Escritura = Fil_Escritura + 1
Wend
End Sub
Empezamos inicializando la variable que leerá las celdas de la columna A Núm_Fila y la que se utilizará para
escribir el resultado final (Fil_Escritura).
A continuación, escribimos el bucle que leerá todas las celdas hasta la última celda no vacía (bucle realizado con la
instrucción WHILE ... WEND).
A continuación, construimos nuestro segundo bucle (instrucción DO ... LOOP) que se parará cuando ya no haya
igualdad en el valor de la fecha entre dos filas. Cuando haya una igualdad, escribiremos el resultado en una misma fila.
Solo la variable que corresponde al número de columna se incrementará.
En cada bucle, incrementamos la variable de la fila que se va a leer, pero no la de la fila para escribir. La variable
Fil_Escritura solo debe incrementarse después del segundo bucle (cuando ya no haya igualdad de fechas).
El test del segundo bucle se realiza al final del bucle. De este modo, el bucle se detendrá justo después de haber
incrementado la variable de lectura de la columna A.
Habrá observado que en este programa reescribimos la fecha cada vez que el programa trata una fila. Sería más sensato
escribir la fecha una sola vez por fila de escritura haciendo un test para evitar tener que reescribir este
dato si ya se ha presentado. Hay distintos modos de hacer este test:
Sub Main()
Dim Núm_Fila As Long
Dim Col_Escritura As Long
Dim Fil_Ecritura As Long
- 6- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Fil_Escritura = 1
Núm_Fila = 1
While Cells(Núm_Fila, 1) <>
"" Col_Escritura = 5
Do
If Col_Escritura = 5 Then
Cells(Fil_Escritura, 4) = Cells(Núm_Fila, 1)
End If
Cells(Fil_Escritura, Col_Escritura) = Cells(Núm_Fila, 2)
Col_Escritura = Col_Escritura + 1
Núm_Fila = Núm_Fila + 1
Loop While Cells(Núm_Fil-a 1, 1) = Cells(Núm_Fila,
1) Fil_Escritura = Fil_Escritura + 1
Wend
End Sub
Otra técnica: habría sido posible escribir la fecha al salir del segundo bucle, y así evitamos realizar un test:
Sub Main()
Dim Núm_Fila As Long
Dim Col_Escritura As Long
Dim Fil_Escritura As Long
Fil_Escritura = 1
Núm_Fila = 1
While Cells(Núm_Fila, 1) <>
"" Col_Escritura = 5
Do
Cells(Fil_Escritura, Col_Escritura) = Cells(Núm_Fila, 2)
Col_Escritura = Col_Escritura + 1
Núm_Fila = Núm_Fila + 1
Loop While Cells(Núm_Fil-a 1, 1) = Cells(Núm_Fila,
1) Cells(Fil_Escritura, 4) = Cells(Núm_Fil-a 1, 1)
Fil_Escritura = Fil_Escritura + 1
Wend
End Sub
En ese caso particular, es necesario devolver el valor de la fecha de la fila anterior. En efecto, en este momento
acabamos de terminar el test de igualdad de la fecha y, por tanto, al salir del bucle, el valor de la fila leída señala
la fecha siguiente. Vamos a escribir la fecha de la penúltima fila leída, es decir Núm_Fila - 1.
Seguimos queriendo leer los datos de hoja1, pero el resultado debe copiarse en hoja2 en la columna A. La tarea puede
parecer compleja, pero, de hecho, es muy sencillo de codificar.
Partiendo del código anterior, vamos a agregar a cada objeto Cells, el objeto Sheets.
Para las celdas leídas, agregamos el objeto Sheets("Hoja1") y para las celdas en las que vamos a escribir, agregamos
el objeto Sheets("Hoja2").
Fil_Escritura = 1
Núm_Fila = 1
WhileSheets("Hoja1").Cells(Núm_Fila, 1) <>
"" Col_Escritura = 2
Do
Sheets("Hoja2").Cells(Fil_Escritura, Col_Escritura) =
Sheets(."CHeoljlas1("N)úm
_Fila, 2) Col_Escritura =
Col_Escritura + 1
Núm_Fila = Núm_Fila + 1
Loop While
Sheets("Hoja1").Cells(Núm_Fila - 1, 1)
= Sheets("Hoja1").Cells(Núm_Fila, 1)
Sheets("Ho.jCae2l"l)s(Fil_Escritura, 1) =
Sheets("Hoja1").Cells(Núm_Fila - 1, 1)
Fil_Escritura = Fil_Escritura + 1
Wend
End Sub
1. Presentación
Este nuevo bucle es una de las funciones más interesantes de Excel. Gracias a ella, se pueden realizar bucles en
colecciones de objetos (como las hojas, los libros, los gráficos, etc.).
En la sección Colección de objetos del Anexo de este manual, encontrará las colecciones de objetos más usuales de
Excel.
A diferencia de los bucles anteriores, en los que las variables contenían valores numéricos que era preciso
incrementar, aquí la variable contiene el conjunto de propiedades del objeto.
La variable que se utilizará debe estar asociada a una propiedad o a un métod o para poder explotarla.
Por ejemplo, desea extraer el nombre de todas las hojas de un libro para escribir el resultado en la columna A de la hoja
Hoja1. El código es el siguiente:
Sub Bucle_Hoja()
Dim Objeto_Hoja As Object
Dim Escrit_Fila As Long
Escrit_Fila = 1
For EacOhbjeto_Hoja In Worksheets
Sheets("Hoja1").Cells(Escrit_Fila, 1) = Objeto_Hoja.Name
Escrit_Fila = Escrit_Fila + 1
Next
End Sub
Mucha información está en la línea FOR EACH: el término WorkSheets indica que el bucle se va a aplicar a la colección
de objetos Hoja: vamos a centrarnos en el objeto "Hoja de cálculo" de nuestro libro y recorrer cada una de
ellas.
Es interesante puntualizar la diferencia entre WorkSheet y WorkSheets. El primer término (sin la s) corresponde al Objeto
Hoja, mientras que WorkSheets (con una s) corresponde a la Colección de Objeto s worksheets (el
conjunto de hojas de un libro). Esto es aplicable para todos los Objetos/Colecciones de Objetos (Row/Rows;
Column/Columns; etc.) que utilice.
La línea FOR EACH puede traducirse del siguiente modo: "Para cada hoja del libro, vamos a trasladar la totalidad de
propiedades de la hoja seleccionada a la variable Objeto_Hoja".
Por lo tanto, la variable Objeto_Hoja no contendrá un valor, sino la totalidad de propiedades de la hoj a sobre la que se
coloque el bucle. La siguiente imagen, que proviene de un depurador, muestra una parte de las propiedades
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
relacionadas con la hoja en la que se coloca el bucle:
En el capítulo siguiente sobre las depuraciones veremos cómo visualizar el conjunto de propiedades de un objeto.
Al final, el programa se interpretará de la siguiente forma: "Para cada hoja de nuestro libro, escribimos su nombre
(propriedad Name del objeto) en una nueva celda.
Desde la página Información, encontrará el archivo Ejemplo 7D que extrae el nombre de todas las hojas del libro y que
genera un reenvío con vínculos hipertexto gracias a la instrucción Hyperlinks.
Sub Navigation()
Dim Mi hoja As Object
Dim Num_Fila As Long
Num_ Fila = 1
For Each Mi hoja In Worksheets
If Mi hoja.Name <> "Sumario" Then
’ Index en el sumario
Sheets("Sumario").Cells(Num_Fila, 1) =Mi hoja.Name
Sheets("Sumario").Hyperlinks.Add _
Anchor:=Sheets("Sumario").Cells(Num_Fila, 1), Address:="", _
SubAddress:=Mi hoja.Name & "!A1", TextToDisplay:=Mi hoja.Name
En el siguiente ejemplo realizamos un código que multiplica por diez los valores de la columna A e inscribe el resultado en la
misma fila de la columna B. Puede descargar el ejemplo desde la página Información.
Sub Bucle_Simple ()
Dim Núm_Fila As Long
For Núm_Fila = 1 To 7
Cells(Num_ Fila, 2) = Cells(Num_ Fila, 1) * 10
Next
End Sub
Solo que, como el contenido de la celda A4 es texto y no un número, el programa es incapaz de efectuar la operación y eso
provoca que aparezca el cuadro de diálogo siguiente:
Tómese siempre el tiempo de leer el origen del error (en este caso la incompatibilidad de tipo). No pulse
Al hacer clic en el botón Depurar, abrirá Visual Basic Editor y verá la línea de código que ha hecho que el programa se parase. En
nuestro ejemplo, nos hemos detenido en la línea que efectúa el cálculo.
La línea de error puede identificarse fácilmente porque aparece siempre subrayada en amarillo.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Pero cuidado, el programa no se ha detenido. Simplemente está en modo pausa.
Si el programa se detiene, no será posible estudiar el valor de las variables o los tests. Si quiere de veras detener la
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Buenas prácticas
Hasta ahora hemos iniciado siempre los programas pulsando el icono de Visual Basic Editor o bien usando el
método abreviado [F5] . Solo que, si el programa es largo y se produce un error inesperado, no será posible detener
la ejecución del programa.
Imagine por un momento que lleva a cabo un programa que cambia el nombre de los archivos y que, en lugar de
hacerlo en su ordenador, lo elabora en el servidor de su empresa ya que no indica la ruta de acceso. Como en VBA la
instrucción "Anular" ([Ctrl] Z) es inoperante, no le costará imaginarse los problemas que su programa puede causar.
Por ese motivo recomendamos siempre iniciar programas en modo Paso a paso ([F8]) durante toda la fase de diseño del programa.
Solo iniciará programas con [F5] una vez que haya controlado todas las etapas y no se produzca ningún error de
ejecución. Yo mismo, tras veinte años de experiencia en programación con VBA, sigo iniciando mis programas con la
tecla [F8] .
En los ejemplos que se irán sucediendo a continuación, procure siempre iniciar los programas en modo Paso a paso.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Lectura "Paso a paso"
La herramienta de depuración presenta dos intereses principales:
1. La tecla [F8]
Para explotar la herramienta de depuración, vamos a retomar el código que hemos utilizado en el capítulo sobre los bucles
para reorganizar una lista de nombres por fecha. El siguiente programa contiene voluntariament e dos errores que
vamos a encontrar gracias a la herramienta de depuración:
Sub Organización_Nombre()
Dim Núm_Fila As Long
Dim Col_Escrit As Long
Dim Fil_Escrit As
Long
Fil_Escrit = 1
Núm_Fila = 1
While Cells(Núm_Fila, 1) <>
"" Col_Escrit = 5
Do
Cells(Fil_Escrit, Col_Escrit) = Cells(Núm_Fila, 2)
Col_Escrit = Col_Escrit + 1
Núm_Fila = Núm_Fila + 1
Loop While Cells(Núm_Fil-a 1, 1) = Cells(Núm_Fila,
1) Cells(Fil_Escrit, 4) = Cells(Núm_Fila, 1)
Fil_Escrit = Fil_Escrit + 1
Wend
End Sub
Inicie el programa en modo Paso a paso pulsando la tecla [F8] . Inmediatamente verá aparecer una línea amarilla al
principio de su procedimiento.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Para hacer avanzar paso a paso el programa, basta con pulsar la tecla [F8]: cada vez que pulse la tecla
[F8] , la línea de código en amarillo se ejecuta y pasa a la línea siguiente.
Si trabaja en un programa que comporta varios procedimientos y funciones, existe un truco muy interesante que
permite ejecutar íntegramente procedimientos o funciones sin tener que pasar Paso a paso por el procedimiento.
En el capítulo siguiente, Estructura de un programa, veremos cómo construir programas con varios procedimientos, pero
aquí solo nos centraremos en el uso del depurador en estos casos.
Imagine que tiene un programa donde hay un procedimiento que lo único que hace es buscar un valor en una tabla de
memoria. Utilizar la depuradora para limpiar fila a fila toda la tabla en memoria es una tarea sumamente
fastidiosa que además no le enseñará nada sobre el desarrollo del programa.
De hecho, cuando se encuentra en la línea de llamada de un procedimiento ( Call) o una función, al pulsar
simultáneamente las teclas [Mayús][F8] , ejecutará el contenido del procedimiento al que se ha llamado sin tener
que pasar todas las líneas del procedimiento en modo Paso a paso.
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Inspeccionar las variables
Ahora que sabe controlar el desarrollo del programa, vamos a visualizar el contenido de las variables durante la
ejecución.
Hasta ahora, para leer el contenido de las variables, hemos visto que podíamos usar el método MsgBox como vimos en el
capítulo sobre las variables, pero este método es desventajoso ya que bloquea la ejecución del programa cada vez que
aparece el cuadro de diálogo personalizado. Por ese motivo, es mucho más eficaz usar la herramienta de inspección para
ver el contenido de las variables sin bloquear la ejecución.
Seleccione la variable que desea observar mediante un clic de arrastre y active el menú Depuración
Inspección rápida...
También puede activar la Inspección rápida mediante la combinación de teclas [Mayús][F9] o haciendo clic en el
icono .
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Haga clic en el botón Agregar, la variable inspeccionada aparece en una nueva ventana llamada
Inspecciones.
Observe que, en este estadio, el valor de la variable es igual a 0. Esto se debe a que el programa aún no ha leído la
línea amarilla. La leerá la próxima vez que pulse la tecla [F8] .
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
La ventana Inspecciones
La ventana Inspecciones le permite visualizar todas las variables que ha seleccionado.
l su nombre,
l su valor,
l su tipo,
l su procedimiento de aplicación.
También puede seleccionar varios datos, como una operación matemática o un test.
Del mismo modo, también puede seleccionar un objeto (como una hoja de cálculo, etc.); en ese caso, la ventana
Inspecciones no muestra directamente la información.
Haga clic en el símbolo situado a la izquierda del nombre del objeto para desplegar todas las
propiedades relacionadas con ese objeto:
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Lo mismo ocurre con las tablas en la memoria. Al seleccionar el nombre de la tabla no verá aparecer
ningún valor, sin embargo, si pulsa sobre el icono situado a la izquierda del nombre de la tabla,
aparecerá todo el contenido de la misma.
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
La ventana de variables locales
Si trabaja en proyectos grandes en los que se administra un gran número de variables, puede resultar muy fastidioso tener
que seleccionarlas unas tras otras para ver su contenido en la ventana Inspecciones.
Para ganar tiempo, puede mostrar todas las variable s del procedimiento en curso de ejecución seleccionando en la barra de
herramientas el menú Ver y, a continuación, el submenú Ventana Locales.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
En este ejemplo podemos ver todas las variables del Módulo1 del procedimiento Main_Pgm (primera información que
aparece justo antes de la ventana).
Si trabaja en un proyecto que contiene varias Sub o Functions, al llamar a una nueva, solo serán visibles las variables
contenidas en el nuevo procedimiento o función y lo mismo ocurrirá para todo el programa.
Las variables locales ya no son las mismas porque el programa está ahora dentro de otra función
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
El punto de interrupción
Para evitar pasar por todo su código en modo Paso a paso, puede colocar un punto de interrupción. El principio es leer el
código de forma normal hasta que el programa alcance el punto de interrupción; a continuación, usted retoma el control en
modo Paso a paso.
Acceda a la línea en la que desea marcar una parada. A continuación, haga clic en el icono o pulse la tecla
[F9] .
También puede utilizar el ratón para hacer clic en el margen gris para mostrar/quitar un punto de interrupción.
Inicie su programa con [F5] . La ejecución se detendrá en el punto de interrupción y la línea amarilla (modo
paso a paso) se superpondrá a la línea roja (punto de interrupción):
Para continuar la ejecución, puede pulsar la tecla [F8] para leer el programa Paso a paso o pulsar la tecla [F5] para
leer el programa de forma continua hasta el próximo punto de interrupción. Si el punto de interrupción está
colocado en un bucle, el programa se detendrá en cada iteración del bucle.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
La instrucción Debug.Print
Cuando tiene un programa que repite varios cientos de veces el mismo bucle, resulta fastidioso tener que pulsar la tecla
[F5] para que el programa continúe después del punto de interrupción.
Para evitar esto, se pueden posicionar "marcadores" que ayudarán a proseguir la ejecución del programa. Al acabar,
bastará con releer los diferentes marcadores para analizar el programa y ver dónde está el error.
Para añadir un marcador al programa es preciso añadir la instrucción Debug.Print seguida del nombre de la
variable que se quiere analizar.
Retomaremos el primer ejemplo de este capítulo y vamos a añadirle la instrucción para seguir el valor de la variable y
también el resultado obtenido.
Sub Bucle_Simple()
Dim Núm_Fila As Long
For Num_ Fila = 1 To 7
Cells(Núm_Fila, 2) = Cells(Num_ Fila, 1) * 10
Debug.Print "Valor de la fila : " & Num_ Fila
Debug.Print "Resultado del cálculo : " & Cells(Num_ Fila, 1) * 10
Next
End Sub
Al acabar de ejecutar el programa, para ver el seguimiento de la instrucción Debug.Print, seleccione la opción
Ventana Inmediato en la barra de menú (o utilice el método abreviado de teclado [Ctrl] G).
Por debajo de las líneas de código verá aparecer sus líneas personalizadas con los diferentes valores de variables y cálculos.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Interrupción según condición
En modo depuración también puede detener la ejecución de un programa cuando una variable alcance un valor. De esta
manera, los bucles se ejecutarán normalmente hasta el momento en que la variable de referencia alcance el valor
deseado.
Imaginemos un documento Excel que contiene 100 celdas conocidas; queremos detener la ejecución del programa cuando
este llegue a la fila 98 (para visualizar la ejecución del código hasta su término).
Vamos a modificar la inspección de la variable Núm_Fila para que el programa se detenga cuando se alcance el valor
98.
En la zona Expresión, indique el valor que debe alcanzar la variable para detener el programa (aquí 98). En la
zona Tipo de inspección, active la opción Interrupción cuando el valor sea verdadero.
Después de confirmar, la ventana Inspecciones ya no muestra en la primera columna el icono sino el icono para
indicar que se trata de una variable de tipo Interrupción.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Inicie su programa pulsando la tecla [F5], el programa se detendrá cuando la variable Núm_Fila alcance el
valor 98.
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Intervenir durante la ejecución del código
En modo Paso a paso, es posible modificar una línea de código ya ejecutada y después volver atrás situándose sobre ella
para interpretarla de nuevo. También es posible modificar el valor de las variables manualmente para actuar
sobre el comportamiento del programa.
1. Vuelta atrás
Imaginemos que tenemos un programa idéntico al primer código de este capítulo, pero con la instrucción
While ... Wend.
Sub Bucle_Simple()
Dim Núm_Fila As Long
Núm_ Fila = 1
While Cells(Núm_ Fila, 1) <> ""
Cells(Núm_ Fila, 2) = Cells(Núm_ Fila, 1) * 10
Núm_ Fila = Núm_ Fila + 1
Wend
End Sub
Inicie el programa.
Ahora supongamos que desea escribir el resultado, no en la columna B, sino en la columna C. En lugar de detener el
programa, cambiar el valor de la columna y volver a iniciar el programa, es posible intervenir en algunos parámetros del
código sin detener la ejecución.
Desplace la línea de ejecución (la línea amarilla) para situarla antes del bucle (justo al principio de la
variable).
Continúe con su programa en modo Paso a paso para iniciar de nuevo el bucle con la nueva columna y
escribir el resultado en la columna C.
En VBA hay elementos que no se pueden modificar cuando el programa se está ejecutando como, por ejemplo, cambiar el
nombre a una variable, modificar el tipo de una variable o cambiar el tamaño de una tabla en memoria.
No le habrá pasado desapercibido que el ejemplo precedente contiene un bucle While ... Wend, mientras que el primer
ejemplo de este capítulo producía el mismo resultado, pero con la instrucción For ... Next.
De hecho, si hubiera querido ilustrar la vuelta atrás con un bucle For ... Next, el programa no habría iniciado la variable
situando la línea de ejecución (la línea amarilla) en la instrucción For. Es el principio mismo de los bucles For ... Next;
la variable se inicia justo entrando en ese bucle. En los demás pasos, el For ... Nextno hace
más que comprobar si se alcanza o no el límite. Por lo tanto, volviendo a situar la instrucción de mi programa en la instrucción
For ... Next, habré proseguido con el mismo valor para Núm_Fila.
Ahora bien, habría podido volver desde el principio de mi bucle For ... Next cambiando yo mismo el valor de la variable.
Para ello, es preciso:
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Abrir la ventana Inmediato (menú Ver, y Ventana Inmediato).
Num_Fila = 1
En la siguiente imagen, he recorrido 5 veces el bucle y mi variable, por tanto, tiene el valor 5 (visible en la ventana
Inspecciones).
Ahora cambio el valor de la variable usando la ventana Inmediato y confirmo pulsando [Entrée] . Observe que el valor
de la variable en la ventana Inspecciones es ahora igual a 1.
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Después del cambio, la variable Num_Fila es igual a 1
El programa se reiniciará desde el valor 1 de la variable, se reiniciará, por tanto, desde el principio del bucle.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 3-
Ejemplo de aplicación de la depuradora
Retomemos el código del principio del capítulo. La ejecución del procedimiento Main da el siguiente resultado en su
hoja de cálculo.
El programa no muestra el primer nombre en la columna E (excepto en la primera fila). Vamos a observar el
comportamiento de la variable Col_Escrit en modo paso a paso; también vamos a observar la variable
Fil_Escrit.
Cada vez que se carga una fecha, la variable Col_Escrit debería tomar el valor 5. Ahora bien, como no se da el caso,
vamos a analizar el comportamiento de las dos variables en la ventana Inspecciones.
Añada una inspección para cada una de las dos variables Fil_Escrit y Col_Escrit.
Inicie el programa en modo Paso a paso (tecla [F8] ) y siga la ejecución hasta que la variable
Fil_Escrit alcance el valor 2.
En este paso, acabamos de terminar la escritura de la primera fila y el resultado en nuestra hoja de cálculo es el
esperado:
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Pulse una vez más la tecla [F8] para volver al principio del bucle.
En este paso, la variable Col_Escrit debería volver a 5, pero no es así, esta no se inicializa. De hecho, esta
instrucción está fuera del bucle principa l (el programa no volverá a pasar por esta instrucción hasta el final).
Para corregir este problema, basta con desplazar la instrucción Col_Escrit = 5 debajo de la línea
While para que la variable Col_Escrit se inicialice después de cada ciclo del bucle While.
De este modo, la variable Col_Escrit se inicializará a 5 antes de cada nuevo bucle Do ... Loop.
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
El resultado parece correcto, pero si observamos con atención las fechas encontraremos un nuevo problema:
tenemos un desfase entre los nombres y las fechas.
Vamos a utilizar una vez más la herramienta de depuración para inspeccionar el comportamiento de la instrucción que
escribe la fecha. Vaya al segundo procedimiento Organización_Nombre.
Cells(Fil_Escrit, 4) = Cells(Núm_Fila, 1)
El programa se detiene justo antes de la escritura de la fecha en la hoja Excel, pero en este estadio, el valor
Núm_Fila es igual a 3.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 3-
El programa recuperará el valor de la celda A3 (13/04/2010) para copiarla en la celda D1.
Para copiar en D1 la fecha esperada (el 12/04/2010), hay que recuperar el valor de la fila anterior. Basta con restar
1 a la variable Núm_Fila.
Sub Organización_Nombre()
Dim Núm_Fila As Long
Dim Col_Escrit As Long
Dim Fil_Escrit As Long
Fil_Escrit = 1
Núm_Fila = 1
While Cells(Núm_Fila, 1) <>
"" Col_Escrit = 5
Do
Cells(Fil_Escrit, Col_Escrit) = Cells(Núm_Fila, 2)
Col_Escrit = Col_Escrit + 1
Núm_Fila = Núm_Fila + 1
Loop While Cells(Núm_Fil-a 1, 1) = Cells(Núm_Fila, 1)
Cells(Fil_Escrit, 4) = CellNsú(m_Fila - 1, 1)
Fil_Escrit = Fil_Escrit + 1
Wend
End Sub
- 4- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Dividir un programa en varios procedimientos
Hasta el momento, hemos creado cada programa en un solo procedimiento. Pero el interés de VBA es poder construir un
programa con varios procedimientos o varias funciones que puedan ejecutarse varias veces a lo largo de la
ejecución.
1. Código inicial
El objetivo del programa es abrir el segundo libro (Cliente.xlsx) y llevar a cabo una selección a partir de la fecha de
nacimiento de los clientes. Con la Grabadora de macros, obtenemos el código que se muestra a continuación. En su caso la
ruta de acceso será diferente, pero enseguida lo corregiremos.
Sub Macro1()
Workbooks.Open Filename:="C:/MisDocumentos/Excel/Cliente.xlsx"
Range("H1").Select
Selection.CurrentRegion.Select
ActiveWorkbook.Worksheets("Hoja1").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("Hoja1").Sort.SortFields.Add _
Key:=Range("H2:H201")
_
, SortOn:=xlSortOnValues, Order:=xlAscending, _
DataOption:=xlSortNormal
With ActiveWorkbook.Worksheets("Hoja1").Sort
.SetRange Range("A1:J201")
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
End
Sub
La primera instrucción corresponde a la apertura del archivo y las demás a las filas de comandos para efectuar la
selección. Vamos a aislar estas dos partes en dos procedimientos distintos.
Los dos programas son rigurosamente los mismos, hemos escrito la instrucción de apertura del libro en un
procedimiento aparte y hemos hecho lo mismo en lo que respecta a la selección. Para continuar ejecutando el
programa como antes, hemos creado un procedimiento ( Procedimiento_Principal) que solo contiene dos
instrucciones: las instrucciones de llamada a otros dos procedimientos con la instrucción Call.
Para iniciar el programa completo, es preciso que el cursor esté en el procedimiento principal y que pulse la tecla [F5] .
O bien, si el cursor está fuera de todos los procedimientos, un cuadro de diálogo le preguntará qué procedimiento
desea iniciar.
3. La instrucción Call
La instrucción Call no es obligatoria para llamar a otro procedimiento, pero aconsejamos vivamente usarla.
Podríamos haber escrito perfectamente el procedimiento principal de la manera siguiente y el programa habría funcionado
igual.
Sub Procedimiento_Principal
Abrir_Archivo
Selección_Datos
End Sub
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Pero conservar la instrucción Call ofrece tres ventajas:
Es fácil localizar todas las llamadas hechas por el proyecto realizando una búsqueda ( [Ctrl] F) con la
palabra clave Call.
En caso de tener que releer un programa, es más sencillo comprender las filas de llamada.
El paso de parámetros es más legible usando la instrucción Call gracias a la aparición de una etiqueta
informativa que indica los parámetros que se esperan.
Mientras el programa sea relativamente pequeño, puede escribir el código en un solo procedimiento. Pero en cuanto tenga
que gestionar un programa mayor, con varios tests y varios bucles, si escribe todo el código en un solo
procedimiento, el programa se hará ilegible enseguida.
La idea de la programación modular es aislar una parte específica del programa (por ejemplo, una condición) en un
procedimiento o en una función. Desde el procedimiento principal, usted hace llamadas a esos procedimientos o
funciones tantas veces como precise usarlos.
Ni que decir tiene que no es obligatorio crear programas con varios procedimientos, pero haciéndolo resulta más fácil
aislar etapas en procedimientos separados y, sobre todo, protege de errores.
En efecto, si se conserva todo el código en un solo procedimiento, modificar un bucle, una variable o un test puede tener
repercusiones sobre todo el procedimiento. Al aislar tareas en procedimientos específicos, nos aseguramos de conservar el
código y el riesgo de errores de ejecución es mucho más limitado.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 3-
Alcance de las variables
Partiendo del caso que nos ha servido de ejemplo al principio de este capítulo, hemos conseguido dividir nuestro
programa inicial en tres procedimientos (uno que administra las llamadas y otros dos que ejecutan las acciones de
apertura de archivos y de selección) sin que ello ocasione el menor error de ejecución.
De hecho, el trabajo de división ha sido sencillo de realizar, ya que no hemos tenido que gestionar el paso de variable de un
procedimiento a otro porque no había ningún parámetro en el programa inicial. Ahora, para hacer el programa más
flexible, vamos a transformar la ruta de acceso y la columna de selección en variable y vamos a ver que la gestión de
llamadas de un procedimiento es más compleja.
Como ya hemos indicado en el capítulo Las variables, una variable declarada en Dim dentro de un procedimiento solo
es visible en el procedimiento donde se ha declarado.
Si declara una variable con la instrucción Dim al principio del módulo, todos los procedimientos y todas las
funciones de ese módulo podrán verla.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
En este caso, el procedimiento 2 puede interpretar el contenido de la variable ya que se ha declarado a nivel del
módulo y los dos procedimientos están en el mismo módulo.
Por el contrario, en el caso siguiente, la variable Mi_Variable no puede interpretarse porque el procedimiento 2 está en
otro módulo.
c. Declaración en Public
Por último, si declara una variable en Public, esta será visible para todos los procedimientos y en todos los
módulos, independientemente del módulo en el que se haya declarado.
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Cuando se declara en Public, la variable es visible para todos los procedimientos y en todos los módulos
2. Dim o Public
Tal y como lo acabamos de presentar, sería tentador declarar todas nuestras variables en Public para que todos los
procedimientos puedan verlas. Es indudable que resultaría más fácil de administrar, pero contradice los principios de un
programa bien organizado.
En efecto, los procedimientos corresponden a funcionalidades concretas como la apertura de un archivo, por ejemplo.
Esencialmente, en ese caso solo necesitamos dos variables: el nombre del archivo y su ruta de acceso. Ahora, si en el mismo
proyecto tenemos un procedimiento que efectúa una selección dentro de una hoja de cálculo,
¿qué interés hay en que este procedimiento tenga la posibilidad de leer las variables que han servido para abrir el archivo? Está
claro que ninguno.
Por ese motivo, es recomendable declarar las variables de manera que solo sean visibles para los procedimientos donde
desempeñan una verdadera función. Con la práctica verá que las variables Public, en general, no son muy
numerosas en los programas.
Pero entonces, ¿cómo transmitir el contenido de una variable Dim declarada en local (es decir, en un procedimiento)
a otros procedimientos o funciones?
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 3-
Parámetros de llamada
Para poder transmitir en el momento de la llamada variables declaradas en local (es decir, generalmente visibles por un
único procedimiento), es preciso pasar las variables como parámetro.
l Indicar que el procedimiento llamado espera un parámetro o más de uno, para funcionar.
Si se quiere indicar que un procedimiento llamado necesita parámetros para funcionar, es preciso indicar el nombre de las
variables que se esperan entre los paréntesis situados tras el nombre del procedimiento (o de la función).
Retomando nuestro ejemplo, quiero que la ruta de acceso de mi libro Cliente.xlsx sea un parámetro en el momento de la
llamada. El procedimiento Abrir_Archivo se escribe ahora de la manera siguiente:
La modificación de código es fácil de entender. Hemos reemplazado la ruta de acceso inicial por una variable y el valor
de esta variable se transmitirá cuando se llame al procedimiento.
Ahora, para indicar el valor de la variable en el momento de la llamada, añadiremos esta información mediante
paréntesis.
Sub Procedimiento_Principal
Call Abrir_Archivo "(C:/MisDocumentos/Excel/")
Call Seleccionar_Datos
End Sub
En el ejemplo precedente, hemos transmitido el valor de la ruta de acceso directamente a los parámetros de llamada.
Hubiéramos podido hacerlo también a través de una variable. En esos casos es imperativo respetar los tipos de variables entre
el procedimiento llamado y el que ha hecho la llamada.
Sustituyo la ruta de acceso por una variable en el procedimiento de llamada y escribo el siguiente código:
Sub Procedimiento_Principal
Dim Rep_Trabajo As String
Rep_Trabajo= "C:/MisDocumentos/Excel/"
Call Abrir_ArchivoR(ep_Trabajo)
Call Seleccionar_Datos
End Sub
¿Usted qué cree?, ¿esta escritura funciona, sabiendo que la variable de llamada es Rep_Trabajo y la variable
esperada tiene el nombre de Ruta_Acceso?
Sí, por supuesto. Si el nombre de las variables difiere entre el procedimiento que hace la llamada y el
llamado, no se producen problemas de interpretación.
Por el contrario, en el programa siguiente, los nombres de las variables son estrictamente los mismos, pero los tipos
de declaración son diferentes (una es un Variant y la otra un String), el programa es incapaz de
interpretar los datos transmitidos durante la llamada y ocasionará un error de ejecución.
Sub Procedimiento_Principal
Dim Ruta_Acceso As Variant
Ruta_Acceso = "C:/MisDocumentos/Excel/"
Call Abrir_Archivo(Ruta_Acceso)
Call Seleccionar_Datos
End Sub
Cuando se llama a procedimientos o funciones, poco importa transmitir referencias de celda, valores, fórmulas o variables. Lo
que cuenta es que el tipo de variable enviado sea estrictamente el mismo que el que se espera.
En esta fase de aprendizaje, puede que le inquieten las informaciones que deben transmitirse a otros
procedimientos:
Pues bien, no es preciso que se plantee todas esas preguntas porque VBA facilita la ayuda necesaria mediante etiquetas
informativas.
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Aquí sabemos al instante que debemos transmitir una sola variable de tipo String correspondiente a la ruta de acceso
de nuestro archivo.
b. Navegación simplificada
Cuando trabaja con proyectos que contienen numerosos módulos que, a su vez, cuentan con numerosas
funciones, podría parecer difícil alcanzar procedimientos llamados entre todas esas filas de código, pero dos trucos lo
hacen muy simple, de hecho.
Para encontrar sin problemas procedimientos llamados, coloque el puntero del ratón sobre el nombre del
procedimiento/función, haga clic con el botón derecho del ratón y después haga clic en Definición.
El editor de código le conduce de inmediato al principio del procedimiento llamado, también cuando el
procedimiento no está en el mismo módulo que la llamada.
También puede seleccionar el procedimiento al que quiere llegar desde la lista desplegable situada encima
del módulo, a la derecha:
También puede mostrar únicamente el procedimiento seleccionado, utilizando las opciones de la parte inferior de
Visual Basic Editor.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 3-
Para ver solo el procedimiento seleccionado, active la vista Ver procedimiento haciendo clic en el icono
: solo se mostrará en la pantalla el procedimiento o la función seleccionados en el menú
desplegable.
3. Flexibilidad de programación
En el ejemplo precedente, para ilustrar la llamada a procedimientos, habíamos transmitido la ruta permanente de acceso
al procedimiento para abrir el archivo. Incluso si el código es exacto desde un punto de vista sintáctico, carece mucho
de flexibilidad.
Si mañana usted cambiara la ruta de su directorio de trabajo, se vería obligado a modificar el código en el programa para
reflejar la nueva ruta.
Para evitar esto, vamos a agregar una función antes de la llamada que determine por sí misma la ruta de acceso. Como
el libro que contiene el código Ejemplo 9A.xlsm, y el libro, Cliente.xlsx, se encuentran en el mismo directorio, usaremos
una funcionalidad de VBA que nos permitirá recuperar la ruta de acceso del libro activo, es decir
ActiveWorkbook.Path .
Sub Procedimiento_Principal()
Dim Rep_Trabajo As String
Rep_Trabajo =ActiveWorkbook.Path
Call Abrir_Archivo(Rep_Trabajo) Call
Seleccionar_Datos
End Sub
No hemos cambiado la llamada al procedimiento ni el código del procedimiento para abrir el libro y aun así sigue funcionando,
independientemente del directorio de trabajo. Ahí reside el interés principal de escribir un programa
con varios procedimientos elementales (que solo efectúan una o dos tareas). Nos basta con modificar los valores de llamada para
cambiar el resultado del programa sin tener que recurrir a pesadas reescrituras del código.
Para ser del todo completo, el código precedente no puede funcionar ya que falta un carácter en la cadena de
caracteres de la ruta de acceso. La instrucción ActiveWorkbook.Path no indica el último "/" de la ruta de
- 4- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
acceso. No es grave porque podemos corregirlo de la siguiente forma:
Sub Procedimiento_Principal()
Dim Rep_Trabajo As String
Rep_Trabajo =ActiveWorkbook.Path & "/"
Call Abrir_Archivo(Rep_Trabajo)
Call Seleccionar_Datos
End Sub
En el capítulo Trabajar con los archivos veremos otras técnicas para recuperar información de los archivos (tamaño, hora
de modificación, etc.).
a. Finalizar el programa
Para acabar de escribir adecuadamente el programa completo, vamos a pasar como parámetro la columna que se escogerá
al llamar al procedimiento Seleccionar_Datos.
En la celda A1 del libro Ejemplo 9 A.xslm, crearemos una lista desplegable igual que habíamos hecho en el
último ejemplo del capítulo Las condiciones. Esta lista mostrará las letras de la A a la J. Recuperaremos la letra
correspondiente a la columna de selección en la llamada de la función.
A continuación, bastará con reemplazar la referencia a la columna de selección por la letra trasmitida por
parámetro en todo el código inicial. El código completo es el que se muestra a continuación y puede encontrarse en el
libro Ejemplo 9C.xlsm:
Sub Procedimiento_Principal()
Dim Rep_Trabajo As String
Dim Columna_Letra As String
’ Variables de trabajo
Rep_Trabajo = ActiveWorkbook.Path & "/"
Columna_Letra = Cells(1, 1)
’ Llamada de los procedimientos
Call Abrir_Archivo(Rep_Trabajo)
Call Seleccionar_Datos(Columna_Letra)
End Sub
En el procedimiento principal, hemos recuperado la columna de selección (variable Columna_Letra) antes de proceder a
abrir el archivo Cliente.xlsx.
¿Por qué tenemos que recuperar la letra de la columna antes de abrir el segundo archivo? Porque después de abrir el
libro Cliente.xlsx, ese es el libro que estará activo y, por tanto, la celda A1 tendrá como valor "Género" (el título de la
columna A del libro Cliente.xlsx) y no el valor de la letra de selección.
A modo de ejercicio, posicione la línea de comando Columna_Letra = Cells(1, 1)después de la llamada a abrir el
archivo. Verá que el programa genera un error de ejecución cuando se efectúa la selección del rango de
datos.
b. Procedimientos invisibles
Encontrará el programa completo en el archivo Ejemplo 9C. Este programa contiene en efecto los tres
procedimientos estudiados, pero cuando se inicia el programa desde la hoja de cálculo pulsando a la vez las teclas [Alt]
[F8] desde Excel (y no desde Visual Basic Editor), solo aparecerá un procedimiento.
De hecho, cuando construimos un procedimiento con al menos un parámetro, es lógico que sea llamado por otro
procedimiento en algún momento del programa. Por lo tanto, solo los procedimientos sin parámetros
(independientes) están accesibles para iniciar un programa, todos los demás procedimientos están invisibles.
- 6- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Las llamadas a funciones
Al final del capítulo sobre la programación en Visual Basic ya mencionamos la diferencia entre procedimientos y
funciones. A modo de recordatorio diremos que las funciones devuelven resultados exactamente igual que lo hacen las
funciones de Excel, mientras que los procedimientos ejecutan tareas específicas.
El ejemplo que habíamos dado era una función sin parámetro a la que se llamaba desde una hoja de cálculo y que
devolvía en su celda el nombre de la hoja activa.
Ahora vamos a ver cómo podemos integrar en los programas funciones personalizadas para efectuar cálculos
personalizados. Si quiere llevar a cabo investigaciones sobre el tema más pormenorizadas en webs anglosajonas, utilice
la palabra clave UDF (User Defined Function).
Escribiremos un programa que nos permitirá convertir las temperaturas en grados Celsius de la columna B en
grados Fahrenheit en la columna C. Es un programa muy sencillo.
Sub Convertir_Grados()
Dim Núm_Fila As Long
Núm_Fila = 2
While Cells(Núm_Fila, 1) <> ""
Cells(Núm_Fila, 3) = Cells(Núm_Fila, 2) * 9 / 5 + 32
Núm_Fila = Núm_Fila + 1
Wend
End Sub
Ahora vamos a transformar el código para aislar la fórmula de conversión de los Celsius en Fahrenheit en una función
aparte.
Si más adelante en el programa debemos recurrir nuevamente a esta fórmula de conversión resulta más sencillo llamar a la
función que se encarga de efectuar el cálculo que escribir la misma fórmula en varias partes del programa.
La escritura de la función se deduce muy fácilmente del programa precedente poniendo la fila de cálculo en una función
personalizada.
Function Fahrenheit()
Fahrenheit = Cells(Núm_Fila, 2) * 9 / 5 + 32
End Function
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Por supuesto, esta función no podrá funcionar así ya que la instrucción Cells(Núm_Fila, 2) no podrá
interpretar la función. Por tanto, la idea es transmitir como parámetro el valor en grados directamente.
Ahora vamos a transformar nuestro procedimiento inicial para que llame a la función personalizada. Simplemente,
remplazaremos la fila de código que efectuaba el cálculo por el nombre de la función personalizada que hemos creado
dándole como parámetro el contenido de la celda. De esta manera:
Sub Convertir_Grados()
Dim Núm_Fila As Long
Núm_Fila = 2
While Cells(Núm_Fila, 1) <> ""
Cells(Núm_Fila, 3) F=ahrenheit(Cells(Núm_Fila, 2))
Núm_Fila = Núm_Fila + 1
Wend
End Sub
Como las funciones personalizadas devuelven un valor, está perfectamente autorizado precisar el tipo de datos que
devolverá la función (aunque no es obligatorio). En nuestro ejemplo podíamos haber escrito:
El tipo de datos que devuelve la función será de tipo Double. Si nuestra función devuelve el resultado de un test, como
la presencia o no de un archivo en un directorio (tal y como veremos en el capítulo Trabajar con los archivos),
nuestra función se declarará como Boolean.
Hasta ahora solo habíamos transmitido variables unitarias a nuestros procesos o a nuestras funciones
personalizadas, pero también es posible transmitir conjuntos de valores usando tablas en memoria.
Lo más simple para ilustrar este punto es crear una función Suma que sumará 10 celdas que se transmitirán en forma de
rango de datos.
Transmitir un rango de datos equivale a transmitir una tabla como argumento. En el ejemplo de abajo, efectuamos la llamada a
la función Mi_Suma transmitiéndole un rango de datos.
Sub Llamada_Función()
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Cells(12, 1) = Mi_Suma(Range("A1:A10"))
End Sub
En el capítulo Las variables ya hablamos del funcionamiento de las tablas. En el capítulo Optimización también
encontrará consejos para mejorar el rendimiento de las tablas mediante la instrucción UBound que devuelve el
tamaño de una tabla.
En nuestro ejemplo resulta muy práctico, ya que sea cual sea el número de celdas que se transmiten como
parámetros, siempre podremos efectuar un bucle entre el primer elemento y el último de la tabla en memoria.
En nuestro ejemplo hacemos un bucle con los valores transmitidos en argumento, pero debemos notar aquí una
diferencia. El primer elemento está en posición 1 (y no 0 como en el caso con la tabla).
La particularidad de transmitir un rango de celdas como argumento es que no se transmiten los valores contenidos en las
celdas, sino un montón de información: el ancho de las columnas, la altura de las filas, los bordes, los nombres de
las celdas, etc. Este es el motivo por el que estamos obligados a declarar el rango de celdas como
Object o Variant.
Es también por esta razón por lo que estamos obligados a precisar que durante el test hecho con la instrucción
UBound nos centramos solo en los valores (Value). Si hubiéramos escrito el nombre del parámetro solo, el
programa no habría podido interpretar nuestros datos.
Por lo tanto, realizaremos un bucle en cada uno de los elementos de la tabla donde hacemos la suma acumulativa de los
valores en la variable Mi_Suma que es también el nombre dado a la función personalizada.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 3-
Ejemplo de aplicación
Uno de los indicadores de análisis bursátil son los medios móviles. El principio es hacer la media de los x últimos días de las
bolsas para encontrar una tendencia. Eso es lo que haremos tomando respectivamente la media de los últimos
10, 20 y 30 días.
Dicho de esta forma podríamos pensar que será preciso escribir largas líneas de código. No obstante, al escribir
programas divididos en tareas unitarias escribiremos, de hecho, códigos muy cortos. Es posible obtener el libro con los
datos brutos desde la página Información, Ejemplo 9E.xlsx.
En primer lugar, concentrémonos en el cálculo de la primera media. Como debemos realizar el cálculo de los diez
últimos días, nuestra primera media se calculará en la celda D11.
Ahora construimos un bucle que recuperará los diez primeros valores, los irá sumando y después, dividirá el
resultado obtenido entre 10.
Sub Pgm_Principal()
Dim i_Fil As Long
Dim Resultado_Sum as Double
For i_Fil = 1 To 10
Resultado_Sum = Resultado_Sum + Cells(i_Fil + 1, 3)
Next
Cells(11, 4 = Resultado_Sum/10
End Sub
Vamos a aislar el bucle que calcula la suma en una función pasando como parámetro las diez primeras cotizaciones en bolsa en
una tabla tal y como hemos visto en el párrafo precedente.
Sub Pgm_Principal()
Cells(11,4) =La_Suma(Range("C2:C11")) / 10
End Sub
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Dim indice_Tab As Long
For indice_Tab = 1 ToUbound(Tab_Valor.Value)
La_Suma = La_Suma + Tab_Valor(indice_Tab)
Next
End Function
La escritura de la función se comprende con bastante facilidad. Hemos trasmitido el contenido de diez celdas a la
función, lo que se traduce por la transmisión de una tabla como parámetro.
A continuación, recorreremos toda la tabla con la variable indice_Tab hasta llegar al último valor de la tabla dado por la
instrucción UBound.
Esta instrucción es muy práctica, ya que sin conocer exactamente el número de elementos que la tabla contiene,
sabemos que leeremos siempre todos los valores de la tabla en memoria. Estamos obligados a especificar .Value
ya que nos centramos solo en los valores transmitidos en la tabla y no en las demás propiedades.
Podemos detallar aún más nuestro código separando el cálculo de la suma y el cálculo de la media, metiendo cada uno en
una función.
Como el cálculo de la media depende del cálculo de la suma (que es en sí misma una función), vamos a utilizar como
parámetro de la función Media, el resultado de la función Suma.
Sub Pgm_Principal()
Cells(11,4) =La_Media(Range("C2:C11"))
End Sub
Por sí mismo verá que las funciones de cálculo de la suma y de la media utilizan a la vez la tabla transmitida para sumar los
valores y el tamaño de la tabla (el número de elementos contenido en su interior) para efectuar la división.
Estas dos funciones se codifican de manera que funcionarán independientemente del número de celdas transmitidas.
Dado que estas dos funciones funcionan en todos los casos, vamos a ponerlas aparte, es decir, en un módulo separado y no
volveremos más a ellas.
Ahora vamos a concentrarnos solo en los bucles que nos permitirán recorrer todas las celdas donde van a calcularse las diferentes
medias.
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
4. Etapa 4: creación del bucle para las filas y explicación del código
Ahora vamos a diseñar el bucle para calcular las medias móviles de todas las celdas de la columna D. Sabemos que el
primer cálculo debe mostrarse en la fila 11 (para contabilizar los 10 datos anteriores). Aquí vamos a utilizar el
valor de la celda D1 para determinar el número de celdas que se debe transmitir a la función.
a. El código
Elaboraremos un bucleWhile que se detendrá cuando el programa llegue a la última celda no vacía de la columna
A y cuando hayamos recorrido 10 filas (test con la función If), transmitiremos el rango de celdas a la función.
Sub Pgm_Principal()
Dim NúmFil As Long
Dim EncabCol As Long
NúmFil = 2
EncabCol = Cells(1, 4)’Valor en celda D1
While Cells(NúmFil, 1) <>
"" If NúmFil > EncabCol
Then
Cells(NúmFil, 4) = _
La_Media(Range(Cells(NúmF-ilEncabCol +
1,3),Cells(NúmFil,3))) End If
NúmFil = NúmFil + 1
Wend
End Sub
Al inicio del programa, en la variable EncabCol recuperamos el valor del encabezamiento (el valor 10 en D1).
Dentro del bucle, llevamos a cabo un test para saber si el valor de la fila leída ( NúmFil) es mayor que el valor del
encabezado de la columna. De esta forma sabremos cuándo tendremos al menos 10 celdas que debemos pasar
como parámetros a las funciones. Por ejemplo, si la variable NúmFil vale 8, habremos leído menos valores de lo
esperado y, por tanto, no llamaremos a la función personalizada para efectuar los cálculos.
Cuando hayamos leído al menos 10 celdas, llamaremos a la función La_Media pasándole como parámetro el rango
de celdas de las 10 celdas leídas anteriormente.
esto, vamos a usar la función Range y usaremos como parámetro las coordenadas de la primera celda
Para escribir
Cells(NúmFil - EncabCol + 1, 3) y la última celda del rango Cells(NúmFil, 3). En el caso de que la
variable NúmFil valga 11, tomaremos las coordenadas de la celda Cells(11-10+1, 3) y de la celda Cells(11, 3).
Para hacer el cálculo de la media de las tres columnas D, E y F, basta con reemplazar el parámetro de la columna en la
instrucción Cells por una variable y crear un nuevo bucle, solo para hacerla variar el valor de las columnas.
Para realizar este último bucle, podemos utilizar la instrucción FOR ... NEXTya que sabemos que debemos hacer
el bucle 3 veces, para los valores 10, 20 y 30.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 3-
Ya solo quedaría reemplazar las referencias que se hacen en la columna 4 por la variable NúmCol.
Sub Pgm_Principal()
Dim NúmFil As Long
Dim NúmCol As Long
Dim EncabCol As Long
ForNúmCol = 4 To 6
NúmFil = 2
EncabCol = Cells(1N,úmCol) ’Valor de los encabezados
While Cells(NúmFil, 1) <> ""
If NúmFil > EncabCol Then
Cells(NúmNFúimlC,ol) = _
La_Media(Range(Cells(Nú-mFEinlcabCol + 1, 3),_
Cells(NúmFil, 3)))
End If
NúmFil = NúmFil + 1
Wend
Next
End Sub
6. Conclusión
Al final tenemos un único procedimiento que efectúa un bucle en las filas y otro en las columnas. También tenemos dos
funciones de cálculo: la primera para el cálculo de la suma y la otra, para el cálculo de la media. El código final es:
Sub Pgm_Principal()
Dim NúmFil As Long
Dim NúmCol As Long
Dim EncabCol As Long
For NúmCol = 4 To 6
NúmFil = 2
EncabCol = Cells(1, NúmCol’)Valor encabezados
While Cells(NúmFil, 1) <> ""
If NúmFil > EncabCol Then
Cells(NúmFil, NúmCol) = _
La_Media (Range(Cells(Nú-mFEinlcabCol + 1, 3),_
Cells(NúmFil, 3)))
End If
NúmFil = NúmFil + 1
Wend
Next
End Sub
- 4- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Function La_Media(Tab_Valor As Variant) As Double
La_Media = La_Suma(Tab_Valor) / UBound(Tab_Valor.Value)
End Function
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 5-
Parámetros opcionales
Cuando se elaboran procedimientos o funciones a partir de parámetros, es obligatorio informar de todos los
parámetros en el momento de hacer la llamada. De no ser así, el programa se detendrá inmediatamente en caso de detectar
que el número de parámetros que se direccionan no se corresponde con el número de parámetros que se esperan.
Existen situaciones en las que elaborar dos funciones prácticamente iguales exceptuando uno o dos parámetros no es
demasiado oportuno, sobre todo para mantener el código.
Para evitar esto, en el momento de crear procedimientos o funciones, podemos indicar que algunos parámetros son o no
obligatorios.
Tomemos el ejemplo de un libro que contiene cantidades y precios unitarios de bienes producidos y también una
columna con el país emisor de la factura.
Deseamos crear una función que calcule el precio sin impuestos en todos los países, pero también queremos que esa misma
función calcule el importe con IVA cuando se trata de España. Para los demás países no es preciso editar el IVA ya que no
será posible recuperarlo.
Nuestro programa de llamada y la función para el cálculo sin IVA se escribe de la siguiente simple manera:
Sub Pgm_Principal()
Dim NúmFil As Long
NúmFil = 2
While Cells(NúmFil, 1) <> ""
Cells(NúmFil, 5) = Precio _ SinIVA _ ConIVA (Cells(NúmFil, 4),
Cells(NúmFil, 3))
NúmFil = NúmFil + 1
Wend
End Sub
Ahora modificaremos la función de llamada para gestionar el cálculo del IVA, pero para ello necesitamos dos
informaciones más: el país y la tasa de IVA. Como esta información no es útil para calcular el precio sin IVA,
indicaremos que esos parámetros son opcionales.
Para indicar parámetros opcionales, es necesario precederlos de la instrucción Optional y es imperativo situarlos al final de los
parámetros.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Para que se tenga en cuenta que la función puede funcionar con parámetros opcionales, escribiremos el programa de la
siguiente manera:
Sub Pgm_Principal()
Dim NúmFil As Long
NúmFil = 2
While Cells(NúmFil, 1) <> ""
Cells(NúmFil, 5) = Precio_SinIVA_ConIVA(Cells(NúmFil,
4), Cells(NúmFil, 3))
Cells(NúmFil, 6) = Precio_SinIVA_ConIVA(Cells(NúmFil,
4), Cells(NúmFil, 3),_ Cells(NúmFil, 2), 0.2)
NúmFil = NúmFil + 1
Wend
End Sub
Precio_SinIVA_ConIVA-=" "
End If
Else
Precio_SinIVA_ConIVA = Precio_U * Ctd
End If
End Function
Si no el parámetro País no está indicado al hacer la llamada, entonces se recibe como vacío en la función, de ahí que
llevemos a cabo un test sobre ese parámetro para saber si debemos considerar o no ese valor en la función.
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Los operadores
Uno de los aspectos clave de la programación es realizar comparaciones entre datos y, en función del resultado de esta
comparación, efectuar un tratamiento específico.
Este capítulo le presentará la lista completa de los operadores que están a su disposición para efectuar tests entre
variables.
Operador Resultado
Si una operación utiliza varios operadores aritméticos, las potencias se calcularán siempre antes que la
multiplicación y la división, que a su vez, se calcularán antes que la resta y la suma.
Para modificar el orden de prioridad de los cálculos, puede emplear los paréntesis.
Por ejemplo:
l 4*4ˆ21/4 = 63,75
l 4*4ˆ(21)/4 = 4
l 4*4ˆ((21)/4) = 5.65
l (4*4)ˆ((21)/4) = 2
Los módulos son operadores poco conocidos, pero son muy útiles para saber si un número es múltiplo de otro. Por ejemplo,
para saber si el número de la celda A1 es un número par, puede escribir el siguiente código:
Para realizar un test a una celda para saber si su valor es un múltiplo de 12, puede escribir el siguiente código:
Los operadores de comparación en VBA son idénticos a los símbolos matemáticos. La tabla siguiente le resume el
conjunto de comparaciones que puede realizar.
Operador Resultado
Existen cuatro operadores lógicos: Or, And, Xor y Eqv. Cada uno de ellos verifica una expresión A y una expresión
B; según el operador lógico escogido, la expresión devolverá el resultado Verdadero (True) o Falso (False):
l El operador Or devuelve True cuando una de las dos expresiones o las dos, son verdaderas.
l El operador And devuelve True solo si las dos expresiones son verdaderas.
l El operador Xor (o O Exclusivo) devuelve True si una sola de las dos expresiones es verdadera (pero no las dos).
l El operador Eqv es la inversa de Xor: Eqv devuelve True si las dos expresiones son idénticas y devuelve False si las dos
expresiones son diferentes.
A continuación, le mostramos cuatro ejemplos para ilustrar cada uno de los casos:
l Para ganar en las carreras de caballos, puede apostar o en orden, o sin orden, pero en los dos casos, usted gana.
Para saber cuáles son los jugadores que ganan, hay que utilizar el operador Or.
l Para que admitan a un estudiante, tiene que tener una media de 5 y ninguna nota inferior a 2,5. Aquí, utilizaremos el operador
And.
l Para contratar a un candidato, el perfil ideal ha de tener, al menos, cuatro años de estudios, o, al menos, cinco años de experiencia,
pero no los dos criterios. Por tanto, utilizará el criterio Xor.
l En caso de contaminación, los coches con matrículas pares tienen derecho a circular los días pares (y viceversa). En este caso, hay
que utilizar el operador Eqv (parpar/imparimpar).
Existe otro operador lógico que invierte el valor de la expresión. Se trata del operador Not.
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Puede escribir las condiciones de dos formas distintas:
También puede incluir paréntesis para dar prioridad al orden de sus tests. Por ejemplo, en caso de que desee
realizar un test a sus clientes. En la columna A, puede indicar Hombre o Mujer y en la columna B, la información de su
estado civil (casado, soltero, viudo, etc.). Si quiere hacer un test de las mujeres solteras o viudas, escribirá el test de la
siguiente manera:
Si prueba el valor Verdadero, no es necesario escribirlo en una condición IF, ya que, por defecto, es lo que la función va a
buscar:
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 3-
Conversión de variable
Muchas empresas trabajan con archivos de texto procedentes de exportaciones de bases de datos. Por ese motivo, los
datos contenidos en esos archivos suelen ser de tipo String, incluidos los valores numéricos. Como no es posible hacer
cálculos con los datos textuale s (String), deberá convertir el tipo de sus variables en uno de los tipos de datos
numéricos existentes.
1. Funciones de conversión
Función Resultado
Pero atención, la conversión de una variable en un cálculo no transforma su tipo permanentemente para el resto del
programa. La conversión solo se aplica para la instrucción o el cálculo en el que se utiliza la variable.
La utilización de una cadena de caracteres en un cálculo provoca la detención del programa. Si tiene dudas sobre el
contenido de una variable, es preferible efectuar un test sobre el tipo.
Se pueden probar dos tipos de datos: los datos que utilizan la función IsDate y los datos numéricos con
IsNumeric.
Por ejemplo, puede realizar el test siguiente para comprobar el tipo de datos contenidos en la celda A1.
Sub Test_Dato()
If IsNumeric(Cells(1,1)) Then
MsgBox "La celda A1 contiene un valor numérico"
Else
La instrucción IsNumeric devuelve Verdadero o Falso; según el valor contenido en la celda A1, se mostrará uno de los dos
mensajes.
En este ejemplo, podemos omitir precisar el test = True, ya que es, por defecto, el valor probado con If. Puede agregar =
True para más claridad, esto no cambiará en absoluto el resultado del test:
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Funciones matemáticas
1. Funciones usuales
Además de los operadores aritméticos descritos anteriormente, el lenguaje VBA posee un gran número de funciones
matemáticas. En la siguiente tabla le mostramos las más usuales.
Función Resultado
Rnd() Devuelve un número aleatorio comprendido entre 0 y 1. Esta instrucción no requiere un parámetro, sin
embargo es aconsejable preceder una función Rnd por la función Randomize para reiniciar el algoritmo
aleatorio.
También puede integrar funciones Excel en un programa VBA. Tomemos por ejemplo el cálculo de la desviación típica de
las celdas A1 a A5.
Los nombres de las funciones están en inglés; para calcular la desviación típica, vamos a buscar la función StDev (diminutivo
de Standard Deviation o desviación típica en español). Los parámetros de esta función corresponden al rango de celdas A1:A5.
La escritura pasa a ser:
Application.WorksheetFunction.StDev(Range("A1:A5"))
Sub Función_Mate()
Dim Resultado As Double
Resultado = Application.WorksheetFunction.StDev(Range("A1:A5")) End
Sub
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Introducción
En VBA, encontrará todas las funciones de Texto de Excel, e incluso, algunas más. Empezaremos presentando todas las
funciones y su uso en casos concretos y después veremos cómo recuperar los datos desde un archivo de texto y
cómo crear un archivo de texto mediante un programa VBA.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Funciones básicas
1. El operador &
a. Utilización en un programa
Antes que nada, es indispensable conocer el operador & y su utilización. Este operador permite relacionar dos
elementos juntos (texto, variable, contenido de celdas, etc.) para hacer solo uno. La utilización de este operador
es realmente primordial en programación y los ejemplos de utilización son infinitos.
Abra el archivo Ejemplo 11B1b. En este archivo, aparece una lista de apellidos en la columna A y una lista de
nombres en la columna B. Para cada una de las líneas del libro, va a crear una hoja que se denominará el Apellido
+ el Nombre.
Comience utilizando la Grabadora de macros para agregar una nueva hoja llamada Nuevo Apellido.
Obtendrá un código similar a este:
Sheets.Add After:=ActiveSheet(1)
Sheets("Hoja2").Select
Sheets("Hoja2").Name = "Nuevo Apellido"
A continuación, integre ese código en un bucle, con ruptura en los apellidos de la columna A de la Hoja 1.
Sub Adición_Hoja()
Dim Núm_Fila As Long
Núm_Fila = 2
While Sheets("Hoja1").Cells(Núm_Fila, 1) <> ""
Sheets("Hoja1").Select
Sheets.Add After:=Sheets(1)
Sheets("Hoja2").Select
Sheets("Hoja2").Name = "Nuevo Apellido"
Núm_Fila = Núm_Fila + 1
Wend
End Sub
A continuación, reemplace "Nuevo Apellido" por la concatenación de las celdas de la columna A y B del
siguiente modo:
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
El operador & se utiliza dos veces en este ejemplo ya que ponemos un espacio " " entre el apellido y el nombre. Sin
este, el apellido y el nombre se unirían uno al otro. Si desea separar el apellido del nombre por un guion, escriba el
código de la siguiente forma:
Para acabar su programa, reemplace la cifra 1 de la instrucción Sheets.Add que indica después de qué
hoja añade una nueva hoja, por la expresión Sheets.Count que devolverá el número de hojas
de su libro. El código final es el siguiente:
Sub Adición_Hoja()
Dim Núm_Fila As Long
Núm_Fila = 2
While Sheets("Hoja1").Cells(Núm_Fila, 1) <> ""
Sheets.Add After:=SheetSsh(eets.Count)
ActiveSheet.Name = Sheets("Hoja1").Cells(Núm_Fila, 1) & " " &
Sheets("Hoja1").Cells(Núm_Fila, 2)
Núm_Fila = Núm_Fila + 1
Wend
End Sub
Atención: muy a menudo, VBA agrega automáticamente espacios entre las instrucciones, pero raramente con el símbolo &.
Con el símbolo & es usted el que tiene que poner los espacios entre cada elemento de una línea de
código para no generar errores de ejecución.
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
2. Las tres instrucciones habituales
a. La instrucción Left
La instrucción Left permite extraer los n caracteres de la izquierda de una cadena de caracteres.
Left(texto; n caracteres)
b. La instrucción Right
La instrucción Right permite extraer los n caracteres de la derecha de una cadena de caracteres.
Right(texto; n caracteres)
c. La instrucción Len
Len(texto)
La utilización de estas tres instrucciones Left, Right y Len le permitirá hacer selecciones determinadas. Por
El número de la habitación puede tener una longitud de 1 o 2 unidades. Por tanto, debemos adaptar el parámetro
longitud de la instrucción Right para devolver cada número.
Como la primera parte de la celda (la palabra Habitación) siempre tiene la misma longitud, utilizando la longitud total
de la celda (con la instrucción Len), menos la longitud de la palabra Habitación (añadiéndole también el
espacio después de la palabra, es decir, 11 caracteres en este ejemplo), obtendremos exactamente la longitud que
debemos seleccionar.
Sub Bucle_Principal()
Dim Núm_Fila As Long
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 3-
Núm_Fila = 1
While Cells(Núm_Fila, 1) <> ""
Cells(Núm_Fila, 2) = Right(Cells(Núm_Fila, 1), _
Len(Cells(Núm_Fila, 1-))11)
Núm_Fila = Núm_Fila + 1
Wend
End Sub
Mid(Texto,Posición de partida,Longitud)
Esta instrucción devuelve una parte de una cadena de caracteres dentro de esta. Por ejemplo, tiene la siguiente lista de
datos:
Cada nombre está compuesto por la palabra Informe, por una fecha y un estado. Para extraer la fecha de cada línea,
hay que recuperar una cadena de caracteres de una longitud de 7 caracteres a partir del 11º carácter (el término
"Informe " cuenta con 10 caracteres con los espacios y el guion).
Escriba un programa como este para extraer la fecha de cada una de las celdas:
Sub Bucle_Principal()
Dim Núm_Fila As Long
Núm_Fila = 1
While Cells(Núm_Fila, 1) <> ""
Cells(Núm_Fila, 2) M=id(Cells(Núm_Fila, 1), 11, 7)
Núm_Fila = Núm_Fila + 1
Wend
End Sub
- 4- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
3. Sustitución
a. Función Mid
La función Mid tiene un segundo uso: también permite reemplazar una parte de los caracteres de una cadena por otros
en un lugar concreto.
Tomando el ejemplo anterior, deseamos reemplazar el carácter "" por el carácter "/".
Sub Bucle_Principal()
Dim Núm_Fila As Long
Dim Cadena_a_tratar As String
Núm_Fila = 1
While Cells(Núm_Fila, 1) <> ""
Cadena_a_tratar = Cells(Núm_Fila, 1)
Mid(Cadena_a_tratar, 9, 1) = "/"
Cells(Núm_Fila, 1) = Cadena_a_tratar
Núm_Fila = Núm_Fila + 1
Wend
End Sub
Atención: la substitución se hace en la memoria. No es posible hacer la modificación y, al mismo tiempo, mostrar el resultado en
la hoja de cálculo.
Ese es el motivo por el cual el contenido de la celda se almacena en la variable Cadena_a_tratar, la sustitución
se hará desde esta variable y el contenido de esta variable se copiará en la misma celda que la celda de origen.
b. Función Replace
La función Replace es más completa que la función Mid. Cuando Mid impone el reemplazo de un carácter por otro en un
lugar concreto, la función Replace, reemplaza 1 o n caracteres en su cadena inicial por otro, y no importa dónde se
encuentren estos caracteres en la cadena. Esta función, por defecto, tiene en cuenta la caja (diferencia entre las
mayúsculas y las minúsculas).
Si, por ejemplo, tiene la palabra "Abracadabra" en la celda A1, la instrucción siguiente tendrá como resultado
"Abricidibri
":
4. Posicionamiento de un carácter
a. La instrucción InStr
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 5-
InStr([Posición de partida], Texto, Texto buscado, [Opción de comparación])
La instrucción InStr (diminutivo de In String, traducido por En la Cadena), devuelve la posición de un carácter o de
un grupo de caracteres en una cadena de caracteres. Si la cadena que busca no está presente, la función InStr devolverá
0.
La función InStr a menudo se emplea en tests para conocer, o no, la presencia de caracteres.
No es necesario especificar la posición de partida si comienza por el principio de la cadena de caracteres (por
defecto, la posición de partida es igual a 1).
Sub Test_Instr()
Dim Valor_Test As String
Dim Resultado As Long
Valor_Test = "El monstruo de las galletas :)"
’Ningún valor para la posición de partida
Resultado = InStr(Valor_Test, "E")
Cells(1,1) = Resultado
End Sub
El valor devuelto en A1 es 1.
La función tiene en cuenta la caja como muestra el resultado de los dos primeros tests con la letra ”e”.
b. La instrucción InstrRev
Por el contrario, si lo que quiere es encontrar la posición de un carácter o de una palabra desde el final de la cadena
de caracteres, la instrucción InstrRev es la más adecuada.
Si se omite la posición de partida, la búsqueda comienza desde el último carácter (valor implícito 1). Por el
contrario, si introduce un valor (por ejemplo 10), la búsqueda invertida comenzará a partir del décimo carácter
partiendo del principio de la cadena de caracteres (partiendo de la izquierda y no de la derecha, como la
instrucción habría podido hacernos pensar).
Tomemos el siguiente ejemplo: desea obtener el nombre del último directorio contenido en la cadena de
caracteres.
- 6- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
En primer lugar, haremos un test simple para saber si el último carácter de la cadena es el símbolo \ (en cuyo caso no lo
tendremos en cuenta), a continuación, recuperamos la posición del carácter \ y extraemos el nombre del último
directorio.
Sub Último_Directorio()
Dim Ruta As String
Dim Último_Dir As
String
Ruta = "C:\Mis Documentos\Usuario\Excel\Proyecto001\"
’Test para saber si el último carácter es \, si sí, se eliminará
If Right(Ruta,1) = "\" Then
Toda la cadena se conserva exceptuando el último carácter
Ruta = Left(Ruta, Len(Ruta)- 1)
End If
Split(Texto, separador)
La función Split le permite cortar una cadena de caracteres según un separador (coma, punto y coma, guion, etc.). Esta
función extraerá automáticamente cada parte de su cadena en una tabla en memoria. No es necesario que gestione el
tamaño de esta tabla, la misma función es la que realiza el trabajo.
En la sección Corte según un carácter de separación de este capítulo, encontrará un ejemplo completo de utilización de esta
función.
Trim(Texto)
Esta función permite "limpiar" toda una cadena de caracteres de los espacios indeseado colocados al principio y al final.
Si solo desea sustituir los espacios del principio de las cadenas, puede utilizar la función LTrim(Texto) y, al
contrario, si desea borrar solo los espacios de la derecha, utilizará la función RTrim(Texto).
7. Mayúsculas y minúsculas
Ucase(Texto)
La función Ucase (Upper Case) permite poner en mayúsculas todos los caracteres de una cadena. También puede utilizar
la función StrConv con la siguiente fórmula:
StrConv(Texto, vbUpperCase)
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 7-
b. Todos los caracteres en minúsculas
Lcase(Texto)
La función Lcase (Lower Case) permite poner en minúsculas todos los caracteres de una cadena.
StrConv(Texto, vbLowerCase)
Para tener, en una cadena de caracteres, sistemáticamente la primera letra en mayúsculas y el resto en
minúsculas, debe utilizar la función StrConv escrita de la siguiente forma:
StrConv(Texto, vbProperCase)
Esta función es muy útil para los nombres compuestos o los archivos musicales (mp3, por ejemplo).
StrReverse(Texto)
Esta función invierte todos los caracteres de su cadena inicial, incluido el orden de las palabras. Se utiliza para
encontrar palíndromos (palabras que se escriben del mismo modo en los dos sentidos como Radar, Kayak,
Reconocer) o también para realizar algoritmos de codificación.
La siguiente imagen le muestra el resultado de una misma cadena con las cuatro funciones de transformación de una
cadena de caracteres.
9. Comparación de cadenas
a. Función StrComp
- 8- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
StrComp(Texto_1, Texto_2, Tipo de comparación)
Sub Comparar_Cadenas()
Dim Comparación As Long
Dim Texto_1, Texto_2 As String
Texto_1 = "ABCD": Texto_2 = "abcd"
Comparación = StrComp(Texto_1, Texto_2, vbBinaryCompare) ’ =-1
Cells (1,1) = Comparación
End Sub
b. Función Like
En su forma básica, la función Like le permite comparar dos cadenas entre sí y reenviar True o False según el
resultado.
Pero la función Like también permite el uso de metacaracteres en los criterios de comparación. La
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 9-
Para comprobar que tiene una dirección de correo electrónico en una celda, puede escribir:
Para comprobar que tiene una dirección de correo electrónico que termina por .es, puede escribir:
a. La instrucción Asc
En un ordenador, cada signo corresponde a una cifra en la clasificación ASCII (American Standard Code for
Information Interchange). El código 65 está asociado con el carácter A y el código 97 está asociado al carácter a
(discriminación mayúsculas/minúsculas).
Para conocer la cifra asociada a un signo cualquiera, utilice la función Asc. El ejemplo siguiente devuelve el valor
65.
Si diseña un programa en el que los usuarios puedan especificar la letra de la columna a partir de la cual se inicia el
tratamiento, podrá escribir el siguiente código:
Si el usuario indica la columna D por ejemplo, Asc ("D") envía el valor 68. A continuación, 6864 envía el valor 4.
Sabrá que el usuario quiere comenzar el tratamiento en la columna 4. Se trata de una técnica diferente a la que
vimos con la instrucción Column.
b. La instrucción Chr
Pero, con los caracteres ASCII, es sobre todo interesante la utilización de un número como carácter. Por ejemplo, la
instrucción Chr permite usar caracteres no imprimibles en el código, como los saltos de línea, por ejemplo. Así, si
quiere ver un mensaje con la función MsgBox en dos filas, tendrá que escribir:
- 10 - © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Chr(13) corresponde a un retorno de carro en la clasificación ASCII. En el anexo E, encontrará la lista de los 32
caracteres ASCII no imprimibles.
Esta función también puede emplearse en los tests del carácter comillas. Como una cadena de caracteres tiene que ir
entre comillas, no podrá escribir """ (tres comillas) para escribir su test. Sin embargo, puede escribir el código
siguiente para comprobar si el primer carácter de su cadena son unas comillas.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 11 -
Leer un archivo de texto
El lenguaje VBA permite acceder a un archivo de texto (.txt, .xml, .bat, .asc, etc.) directamente en la memoria, sin
tener que abrirlo en una hoja de Excel. De este modo, puede recorrer todo un archivo y seleccionar solo los
elementos que desea recuperar en ese archivo.
Vamos a ver en las siguientes secciones cómo abrir, leer, extraer y cerrar un archivo de texto. Después pondremos en
práctica estas técnicas en un caso real de importación de datos.
l el tipo de acceso,
l el número de atribución.
Es necesario que el archivo exista y que la ruta de acceso sea correcta. Puede o bien poner la ruta completa entre
comillas o utilizar variables.
Muy a menudo, el carácter \ que separa la ruta de acceso y el nombre del archivo se omite: ¡no lo olvide, o no podrá abrir el
archivo!
b. El tipo de acceso
Es absolutament e necesario que especifique si accede a un archivo de lectura (Input) o de escritura (Output). Sin
este parámetro, su archivo no se podrá abrir nunca.
c. Número de archivo
Para cada archivo que abra, tendrá que concretar un número de orden que permitirá identificar sus archivos durante el
tratamiento. Puede gestionar usted mismo los números (1, 2, 3,...) o pedirle a VBA que gestione esos
números mediante la instrucción FreeFile.
Para nuestro ejemplo, podemos escribir la siguiente instrucción que abrirá nuestro archivo de texto:
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
2. Leer una línea
Para recuperar una línea del archivo, hay que utilizar la instrucción Line Input sin olvidar precisar el número de archivo
(recuerde no omitir el signo #).
La línea leída se transmitirá a la variable que figura tras la coma, aquí la variable Cadena_Leída.
3. La instrucción EOF
EOF(Número de archivo)
A diferencia de un bucle While, que comprueba si una celda está o no vacía para detenerse, no es posible detectar el final de
un archivo de texto de otra forma que mediante la instrucción EOF, (End Of File).
Esta instrucción reenviará Verdadero si se alcanza el final del archivo. El test se realiza en el número de archivo en el
parámetro. Al integrar esta instrucción en un bucle con condición, podemos detectar si se alcanza el final del bucle o no.
While EOF(1)
Instrucción
Wend
4. Cerrar un archivo
Después de abrir un archivo, nunca debemos olvidar cerrarlo para liberar el número del archivo de la memoria.
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Crear un archivo de texto
El VBA también permite crear archivos de texto. Esta función es muy útil cuando se tienen que enviar datos de la hoja
de cálculo a una base de datos o bien diseñar un archivo de eventos (archivo log).
1. Crear un archivo
Crear un archivo consiste en usar la instrucción Open, pero definiendo el acceso como Output (salida). Después de leer
esta línea de código, VBA crea un archivo vacío con el nombre especificado.
Atención: si en su ordenador ya hubiera un archivo con el mismo nombre, este sería remplazado por el nuevo sin mediar
mensaje de aviso previo .
Para escribir datos en un archivo en salida, utilice la instrucción Print seguida del número de archivo
correspondiente al número de orden atribuido en el momento de abrirlo.
Para guardar una línea en el archivo, bastará con que ponga todos los datos en una sola variable.
3. Declarar variables
Para crear archivos de texto deberá declarar todas las variables de tipo String (lo que no deja de ser lógico, ya que
estamos diseñando un archivo de Texto). Las variables declaradas en String pueden tener una longitud fija.
Todos los elementos copiados en la variable tendrán entonces la misma longitud (definida por la cifra que sigue al
símbolo *).
4. Ejemplo de aplicación
columna D, apellidos,
l en la columna E, nombres.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Tiene que transmitir estos datos a una base de datos que le impone una estructura fija para cada campo:
Deberá crear, por tanto, un archivo de texto que respetará la longitud dada. El código será así:
Sub Crear_Archivo_Texto()
Dim Ruta As String
Dim Archivo As String
Dim i_Fil As Long
Dim CP As String * 5
Dim Ciudad As String * 30
Dim Ref As String * 9
Dim Apell As String * 25
Dim Nombre As String * 15
Sustituya "C:\Su_Ruta" por la ruta de acceso al lugar en que deberá guardarse el archivo conservando las
comillas.
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Encontrará el código de este ejercicio en el archivo Ejemplo 11D4.
5. Ejercicios de aplicaciones
Antes de presentar los dos ejercicios de aplicaciones que vienen a continuación y que no son simples , es
importante hacer un paréntesis para presentar una nueva herramienta: Power Query.
Power Query es una herramienta disponible con Excel 2016 en la pestaña Datos y con Excel 2013, en forma de
módulo complementario (addin) que puede descargarse de forma gratuita en esta dirección:
https://www.microsoft.com/eses/download/details.aspx?id=39379
Power Query es una herramienta que ha sido desarrollada para facilitar la importación de datos, no solo para
archivos de texto, y la manipulación de datos (separación en columnas, eliminación de líneas concretas, cambio de un
documento en columnas a un documento en filas, reagrupación de datos, fusión de columnas, etc.).
Power Query se usa de la misma forma que la Grabadora de macros: todas las manipulaciones efectuadas son
guardadas con el fin de repetirlas. Y, contrariamente a VBA, no es en absoluto necesario entrar en el código para
personalizar la importación. El uso del lenguaje de programación de Power Query lenguaje M se reserva a casos
muy específicos.
Por tanto, si los elementos que necesita automatizar conciernen a importaciones de archivos y las manipulaciones de
datos, puede ser más oportuno trabajar con Power Query que usar la Grabadora de macros. Esto le permitirá ganar
mucho tiempo y, sobre todo, mantener el proceso de importación será mucho más fácil con Power Query que con VBA.
Descargue desde la página Información el documento Ejemplo 11D5.txt que contiene información
extraída de una base de datos. Desea incorporar esta información en un libro de Excel.
Desafortunadamente, en este ejemplo (procedente de un caso real de empresa), no hay delimitador de columnas como
tabulaciones o puntos y coma. Deberemos basarnos en la línea de títulos y en los espacios entre los
encabezamientos de columna para determinar los elementos que vamos a extraer.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 3-
Para abrir, leer, hacer un bucle y cerrar un archivo, hay que escribir un código similar a este. Todas las
instrucciones usadas aquí ya han sido vistas en los apartados precedentes.
Sub Leer_Archivo()
Dim Cadena_Leída As String
Close #1
End Sub
Cada vez que se vuelve a pasar por el bucle, leemos una nueva fila del archivo. El incremento de filas se gestiona
automáticamente por la instrucción Line Input.
Corte en columna
El código que cortará nuestro archivo de texto inicial en columna se puede escribir en el mismo procedimiento justo
después de la instrucción Line Input o bien en un nuevo procedimiento para separar bien las tareas en el
programa:
Última_Fil = Cells(Rows.Count,1).End(xlUp).Row
Última_Fil = IIf(Cells(1, 1) = "", 1, Última_Fil + 1)
Cells(Última_Fil, 1) = Trim(Mid(Texto_A_Tratar, 1, 9))
Cells(Última_Fil, 2) = Trim(Mid(Texto_A_Tratar, 10,
11)) Cells(Última_Fil, 3) = Trim(Mid(Texto_A_Tratar,
22, 32)) Cells(Última_Fil, 4) = Trim(Mid(Texto_A_Tratar,
55, 8))
End Sub
En este procedimiento empezamos recuperando el número de la última fila conocida en la hoja de cálculo gracias a la instrucción
Cells(Rows.Count,1).End(xlUp).Row . Habríamos podido poner simplemente el valor 1 y así
empezar siempre la importación en la fila 1. Solo que si construimos así el programa, no podemos encadenar las
importaciones de archivos sin amontonar los datos anteriormente importados.
La instrucción se comprende de la siguiente manera: nos colocamos ficticiamente en la última celda de la columna A de
nuestra hoja de datos Cells(Rows.Count,1) y volvemos a subir hacia arriba hasta la última celda no vacía que
encontremos End(xlUp). Así Excel se colocará en la última celda conocida de la columna A y devolverá
- 4- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
el número de la fila (Row).
Solo debemos tener en cuenta un caso adicional, el caso en que la columna A está completamente vacía. En ese caso, si
la celda A1 está vacía empezaremos el programa en la fila 1, si no nos situaremos justo después de la
última celda no vacía. Este test se escribe usando simplemente la función Iif.
Por último, cortamos nuestro archivo en cuatro trozos de longitud conocida y colocamos el resultado en cuatro
columnas de la hoja de cálculo. Para escribir el resultado sin ningún espacio inútil, limpiamos los datos de la
extracción con la función Trim.
Habríamos podido sustituir el primer Mid por un Left, pero para la continuación del tratamiento, es preferible
utilizar Mid en cada corte.
Escrito con estos dos procedimientos, nuestro programa ya funciona perfectamente, pero se puede perfeccionar ya que
esto implica que nuestro archivo de entrada tenga una estructura siempre idéntica y un número de columnas
siempre igual a 4.
Si de entrada tenemos varios archivos con un número de columnas diferente, deberemos hacer el programa más
flexible adaptándonos a la estructura del archivo de entrada.
No cabe duda de que diseñar un programa que se adapte a la estructura de cualquier archivo en entrada lo hace más
complejo. No se desanime si no comprende las explicaciones a la primera lectura. Tómese el tiempo de analizar el
código del archivo y volver más tarde a las explicaciones de cada línea de código.
Usaremos también numerosas funcionalidades vinculadas a la tabla en memoria, así que si no está muy
familiarizado con el uso de tablas en memoria, le aconsejamos que lea las detalladas y sencillas explicaciones del
capítulo Optimización Las tablas en memoria.
Para determinar la estructura del archivo en entrada, se deben tener en cuenta dos elementos:
l el número de columnas;
Para obtener este resultado, vamos a basarnos, no solo en los espacios del encabezamiento de las columnas, sino
también en el primer carácter inmediatamente después de una serie de espacios.
l al final del tratamiento, el número de columnas de nuestro archivo, correspondiente al número de pasadas del bucle.
Vamos a hacer un bucle en cada uno de los caracteres de la primera fila hasta alcanzar el último carácter. Para cada columna
detectada, vamos a guardar en una tabla en memoria el número de caracteres de la columna.
Como la estructura del archivo de texto es un elemento central del programa, debemos declarar la tabla, no en un procedimiento
como hemos hecho en cada ejemplo, sino en la parte superior de hoja Módulo para que los datos de la tabla sean visibles
por los procedimientos. Por ese motivo la tabla se declara fuera de todos los
procedimientos en Public, pero sin precisar su dimensión.
Efectivamente, no conocemos el número de columnas presentes en el archivo de texto, vamos a abrir y cerrar un
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 5-
paréntesis sin valor. Sin embargo, en el programa, estaremos obligados a redimensionar la tabla antes de añadir una
nueva columna.
El código completo para obtener la estructura del archivo está descrito a continuación y podrá encontrar el ejemplo
completo en el archivo Ejemplo 11D5b2.
Option Explicit
’ -----------------------------------------------------------------------------
’ Procedimiento de detección de la posición de las columnas
’
----------------------------------------------------------------------
------- Sub Estructura Archivo()
Dim t_col() As Long ’Tabla determinar el valor del inicio de cada columna
Dim i_car As Long ’Indice para los caracteres Dim
i_tab As Long ’Indice el tamaño de la tabla Dim
Línea_A_Tratar As String
- 6- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
En la siguiente figura, aparece el resultado contenido en la tabla en la memoria gracias al depurador.
Ahora que hemos construido un programa capaz de detectar de manera precisa el número de columnas y el número
de caracteres que componen cada columna, nos queda transformar nuestro procedimiento
Separación_Columna para que tenga en cuenta esos datos. Para ello retomaremos las informaciones que
habíamos almacenado en la tabla t_col.
Para determinar el número de caracteres que vamos a extraer, simplemente leeremos en la tabla dos valores
contiguos ( i_tab e i_tab+1), y realizaremos la sustracción.
’ -----------------------------------------------------------------------------------
’ Procedimiento de cumplimentado de la hoja Excel utilizando la estructura de columnas
’
---------------------------------------------------------------------------
-------- Sub Separación_Columna(Texto As String)
Dim i_tab As Long
Dim Última Fila As Long
El índice que usamos para recorrer la tabla se utiliza también para determinar la columna de escritura.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 7-
Gestión de las llamadas de los procedimientos
Acabamos de escribir dos nuevos procedimientos, uno para detectar la estructura de las columnas y otro para dividir
nuestro archivo en columnas. En el primer módulo, justo después de leer una línea del archivo de texto, deberemos
llamar a estos dos nuevos procedimientos.
Para recuperar una sola vez la estructura del archivo de texto durante la lectura de la primera línea del archivo,
aconsejamos añadir un test gracias al uso de una variable booleana (Verdadero o Falso):
Sub Leer_Archivo()
Dim Cadena_Leída As String
Dim Encabezamiento As Boolean
Close #1
End Sub
El código completo puede parecerle complejo pero, de hecho, es mucho mejor programar a través de varios
módulos que con un solo módulo en el que define una estructura estática.
El hecho de haber escrito el programa en tres procedimientos tiene como ventaja aislar cada componente:
l acceso al archivo,
Así, en caso de modificación de su código, es más fácil modificar un solo procedimiento que un programa completo.
Al igual que el comando Convertir de la pestaña Datos de Excel, que le permite sementar el texto en varias columnas
basándose en un carácter de separación, puede hacer el mismo trabajo en VBA gracias a la función
Split.
- 8- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
El archivo Billar.txt contiene las coordenadas GPS de las salas de billar de España. Como podrá comprobar en la
siguiente imagen, el archivo no está estructurado con columnas de ancho idéntico.
Observamos, sin embargo, que la coma hace las veces de separador de las columnas. Vamos a realizar la
extracción basándonos en este símbolo.
Además, queremos seleccionar únicamente las filas que contengan la información [Billar] y excluir aquellas que
contengan [Billar nv].
Vamos a construir un test que comprobará si la cadena de caracteres [Billar] (incluyendo los corchetes) existe en la fila
leída del archivo de texto. La adición de los corchetes es importante para marcar la diferencia con las filas que
contienen el término [Billar nv]. El test consistirá en comprobar que la cadena [Billar] existe mediante la
instrucción InStr:
Si el término [Billar] se encuentra en la variable Extract, la instrucción InStr devolverá una cifra equivalente a su
posición en la cadena leída. Por el contrario, si no se encuentra el término, InStr devolverá 0. Por lo tanto,
podemos hacer un test que verifique que InStr es mayor que 0, lo que significará que se ha encontrado la
cadena buscada.
A continuación vamos a gestionar la extracción de los datos de la tabla con la función Split. Nuestro
procedimiento, se escribirá:
Sub Leer_Archivo_Coma()
Dim Extract As String
Dim Tabla_Extracción As Variant
Dim Ruta As String
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 9-
’Apertura del archivo
Open Ruta & "Billar.txt" For Input As #1
Line Input #1, Ext’rLaeccttura primera fila del archivo
End Sub
En una sola instrucción hemos almacenado toda la fila leída en la tabla con tantas dimensiones como caracteres de
separación existían.
Para escribir los datos de la tabla en una hoja de cálculo, podemos escribir un segundo procedimiento, usando como
parámetro la tabla que vamos a tratar.
Recordemos que el nombre de la variable empleada como parámetro puede ser distinto entre los dos
procedimientos, pero el tipo de variable debe ser obligatoriamente el mismo entre el procedimiento de llamada y el
procedimiento llamado.
- 10 - © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Como podrá comprobar, el procedimiento es casi el mismo que el que se usa en el ejemplo anterior para la
extracción de columnas. Esto prueba que un código totalmente codificado con parámetros puede reutilizarse muy
fácilmente en otros programas.
Obtenemos el resultado esperado, pero, ahora deseamos segmentar los datos de la columna C por el carácter
”espacio”.
Para segmentar la información de la columna C, vamos a volver a usar la función Split. Podemos escribir:
Sub Tratamiento_Columna_C()
Dim Núm_Fil As Long
Dim i_tab As Long
Dim Tabla_Extracción As Variant
Núm_Fil = 1
While Cells(Núm_Fil, 3) <> ""
Tabla_ExtracciSópnli=t(Cells(Núm_Fil, 3),
"") i_tab = 0
Do
ActiveSheet.Cells(Núm_Fil, i_tab + 4) =
Trim(Tabla_Extracción(i_tab))
i_tab = i_tab + 1
Loop While i_tab <= Ubound(Tabla_Extracción)
Núm_Fil = Núm_Fil + 1
Wend
End Sub
Esta vez, no recorremos todo el archivo de texto sino solo la columna C desde la fila 1. Para cada celda leída, utilizamos la
función Split para almacenar en la memoria cada subcadena. El resultado se inscribe en la columna D
(en el programa, la columna D se traduce por el valor i_tab + 4).
El resultado no siempre es satisfactorio ya que para los números de provincias inferiores a 10, perdemos el 0 del principio. A
continuación, para el nombre de las ciudades compuesto por varias palabras tenemos la información escrita en varias columnas
como vemos en la imagen siguiente:
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 11 -
Concatenación de las ciudades
Para ello, tendremos que crear toda una serie de condiciones muy complejas para tratar todos los casos posibles: En
efecto, la información contenida en la columna C no está nada estructurada. Tras el nombre de la ciudad, puede
haber:
número de teléfono.
Por lo tanto es absolutamente necesario realizar tests para cada caso, lo que supone un código enormemente
pesado.
Como verá, es preferible trabajar con archivos bien estructurados para evitar tener que tratar un gran número de casos de test
y cargar inútilmente sus programas.
Por último, también hay que realizar un test para gestionar la extracción de las ciudades compuestas por una o varias
palabras.
Sub Tratamiento_Columna_C()
Dim Núm_Fil As Long
Dim i_tab As Long
Dim Tabla_Extracción As Variant
Dim Nombre_Ciudad As String
Dim Max_Dim_Tabla As Long
Dim Test_Fin_Bucle As Boolean ’Variable que le servirá para dejar
de recorrer la tabla en la memoria.
Núm_Fil = 1
While Cells(Núm_Fil, 3) <> ""
Tabla_Extracción = Split(Cells(Núm_Fil, 3), "")
’Tratamiento de la provincia
If i_tab = 1 Then
- 12 - © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
ActiveSheet.Cells(Núm_Lín’ea", &4)
= " Trim(Tabla_Extracción(i_tab))
Else
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 13 -
Introducción
La utilización de las fechas en un programa no es siempre cosa fácil ya que estas responden a un cierto número de
reglas que deben tenerse en cuenta cuando desea explotar:
l Los días como el sábado o el domingo pueden no contabilizarse (cálculo de días laborables).
La mayor parte de las funciones de Fecha integradas en Excel se presentan en lenguaje VBA. Vamos a ver, con
ejemplos concretos, cómo adaptar las diferentes funciones para manipular las fechas y después veremos a través de
funciones personales cómo diseñar una función que permita devolver el día de Pascua (sea cual sea el año) o cómo
calcular el número de la semana.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Introducción a las fechas
Antes que nada, es importante recordar que para utilizar las funciones de Fecha (en Excel o en VBA), el contenido de las
celdas debe estar en formato Fecha; este formato se define, no con Excel, sino con los parámetros de
configuración del sistema operativo instalado en su ordenador (Windows).
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Es posible personalizar aún más la configuración de la Fecha seleccionando el menú Cambiar formatos
de fecha y hora para especificar la vista y el formato de las fechas.
Para comprobar si el contenido de una celda es una fecha (o un dato numérico), este dato debe estar alineado a la derecha
de la celda; el texto está alineado por defecto a la izquierda de la celda.
En la mayoría de países, los dos separadores de fecha admitidos son los símbolos / y . Pero en ciertos países como Alemania, por
ejemplo, el símbolo empleado es el punto (.) : si usted recibe un archivo que se ha generado desde un ordenador configurado
con parámetros alemanes, lo más probable es que tenga una fecha con formato
31.12.2016. Al importar a un ordenador español, este dato no se reconocerá como fecha sino como texto.
En otros países, el orden de los elementos que constituyen la fecha no es el mismo que en España. Por ejemplo, en
Estados Unidos, el mes precede a los días: el 31 de diciembre de 2016 escrito en versión americana sería
12/31/2016. Incluso en este caso, un ordenador con configuración española no podrá interpretar esta fecha como formato
fecha.
Puede incluso darse el caso de que trabaje con fechas con formato AAAAMMDD (20161231). Este formato de fecha
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
se usa en las grandes bases de datos ya que, en una clasificación en orden decreciente, la fecha más reciente estará
siempre en primera posición. Pero cuidado, al estar escrito de esta manera, es muy probable que Excel interprete
esta información como si fuera un número (20161231 = veinte millones ciento sesenta y un mil doscientos treinta y uno) y
no una fecha.
Una manera sencilla de saber si el dato que va a manipular es una fecha o no, consiste en hacer un test mediante la
instrucción:
IsDate(Dato)
Esta instrucción devolverá Verdadero si el dato es una fecha y Falso en el caso contrario:
If IsDate(Cells(1, 1) Then
MsgBox "La celda A1 contiene una fecha"
Else
Del mismo modo que con Excel, con VBA puede escribir una fecha de varias maneras definiendo el formato mediante la
instrucción FORMAT:
El argumento del formato corresponde a todos los tipos de formato de número que Excel recoge. La única diferencia entre
Excel y VBA es que los parámetros de las fechas deben escribirse en inglés . Por ejemplo, el parámetro para el año no se
expresará mediante una a, sino mediante una y (inicial de year en inglés).
Por ejemplo, para la fecha del 05/07/2017 podemos tener como parámetro de fecha, los siguientes argumentos:
Formato Resultado
d 5
dd 05
ddd miér
dddd miércoles
m 7
mm 07
mmm Jul
mmmm Julio
y 17
yy 17
yyy 2017
yyyy 2017
Y evidentemente, combinándolas todas juntas, podemos visualizar una fecha de diferentes formas:
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 3-
Formato Resultado
d mmm yy 5 Jul 17
Puede utilizar como separador de fecha, los espacios, los guiones o las barras oblicuas. En todos los casos, debe escribir
el argumento del formato entre comillas.
- 4- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Las funciones básicas
Hay cuatro funciones que devuelven la fecha y la hora del sistema de su ordenador. Es frecuente recurrir a estas
funciones para realizar tests entre una fecha cualquiera y la fecha de su ordenador, por ejemplo:
l Test entre la fecha actual y una fecha de entrega en caso de superación de un plazo,
l Test entre la fecha actual y una fecha de cumpleaños en caso de igualdad del mes y del día,
l Test entre la hora actual y una hora de partida para cálculos de superación horaria (trabajo, alquiler, etc.).
DATE
Esta función devuelve la fecha del sistema de su ordenador según el formato definido en su ordenador (generalmente
DD/MM/AAAA). Se comporta como la función HOY en Excel.
TIME
TIMER
Esta función devuelve el número de segundos transcurridos desde la medianoche con una precisión del orden de la
fracción. Es la única instrucción en VBA que devuelve las fracciones de segundo.
NOW
Esta función devuelve la fecha y la hora actual de su ordenador exactamente como la función AHORA de Excel.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Las funciones de extracción
Existen funciones que permiten extraer cada elemento de una fecha y de una hora. Estas funciones son muy
sencillas, pero es importante conocerlas para poder hacer manipulaciones en las fechas y así diseñar fechas
dinámicas.
Las fechas se componen de un día, un mes y un año. Cada parte puede extraerse mediante tres instrucciones:
Day (Date)
Month (Date)
Year (Date)
Del mismo modo, las horas se componen de horas, minutos y segundos. Cada parte puede extraerse mediante tres
funciones:
Hour (Time)
Minute (Time)
Second (Time)
En VBA no es posible extraer una fracción de hora inferior al segundo. Es bastante penalizador cuando se trata de determinar
la velocidad de ejecución de un programa, ya que, en este caso particular, es necesario conocer las décimas, las centésimas y
las milésimas. En el capítulo Optimización veremos cómo resolver este problema.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
La instrucción DateSerial
DateSerial(Año,Mes,Día)
Esta instrucción es muy útil para hacer manipulaciones, cálculos en las fechas y para convertir números en fechas.
Supongamos, por ejemplo, que la celda A1 contiene el valor 20121231 y que desea convertir este valor en fecha.
En primer lugar, va a recortar el contenido de la celda A1 mediante las funciones Left, Right y Mid, y después va a
utilizar la instrucción DateSerial para efectuar la conversión:
De esta forma, el dato de la celda B1 será una fecha y no un número. Observe que las barras oblicuas (/) se añaden
automáticamente en la conversión.
La instrucción DateSerial permite hacer toda clase de cálculos en los elementos de una fecha. Por ejemplo, a
partir de la fecha 31/12/2012 contenida en la celda A1, deseamos realizar cálculos para obtener otras fechas:
l Añadir 32 días:
l Añadir 2 meses:
Da como resultado 03/03/2013. Normalmente, tendríamos que haber tenido como resultado 28/02/2013, pero como el
parámetro de los días es de 31, la función añade 3 días.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
3. Manipulación de las fechas
Ahora, ¿cómo hacemos para obtener como resultado la fecha del 01/10/2012 a partir del 31/12/2012? Lógicamente,
deberíamos restar 3 meses y añadir 1 día. Ahora bien, el resultado devuelto es 02/10/2012.
¿Cómo se explica este resultado? Con los parámetros que hemos escrito, la fecha calculada es el 32/09/2012; como esta
fecha no puede existir y el mes de septiembre solo tiene 30 días, la función añade 2 días al mes siguiente para dar como
resultado el 02/10/2012. Entonces, ¿cómo lo hacemos?
Para devolver fechas específicas (como el primero o el último día de un mes) debemos utilizar otro método. Basta con
reemplazar el parámetro de los días por el valor 1 para devolver el primer día de cualquier fecha.
DateSerial(Year(Date); Month(Date); 1)
De esta manera, sea cual sea la fecha del sistema, esta instrucción devolverá siempre el primer día del mes. Del
DateSerial(Year(Date); Month(Date) + 1; 1)
Ahora, para encontrar el último día de un mes, es necesario recordar la regla básica de las fechas en VBA: el valor 1
equivale a un día .
Así, sea cual sea la Fecha, esta instrucción devolverá siempr e el último día del mes:
DateSerial(Year(Date); Month(Date) + 1; 1) - 1
4. Meses en letras
La instrucción MonthName permite convertir un número en un mes escrito con letras. Por ejemplo, si tiene el valor
9, la siguiente escritura le dará la indicación Sept o Septiembre.
De igual modo, la función WeekDayName devuelve el día en letras a partir de números del 1 al 7.
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Tiene un documento que representa las notas de los gastos para el mes de enero. Para evitar volver a copiar once veces la
hoja Enero y después cambiar manualmente el nombre de las hojas, puede construir una macro:
Utilice la Grabadora de macros para crear una copia de la hoja Enero y cambiar el nombre. El código
obtenido es:
Sheets("Enero").Select
Sheets("Enero").Copy After:=Sheets(1)
Sheets("Enero (2)").Select Sheets("Enero
(2)").Name = "test"
Podemos reducir la escritura de las dos últimas líneas en una sola, ya que cuando se agrega una nueva hoja, esta pasa a
ser automáticamente la hoja activa. Podemos escribir:
Sheets("Enero").Copy After:=Sheets(1)
ActiveSheet.Name = "test"
Ahora vamos a crear un bucle que irá del mes de febrero al mes de diciembre. Por lo tanto, el bucle empezará por 2 y
acabará por 12.
Sub Añadir_Hoja()
Dim Mi_Mes As Long
For Mi_Mes = 2 To 12
Sheets("Enero").Copy After:=Sheets(1)
ActiveSheet.Name = MonthName(Mi_Mes, False)
Next
End Sub
Nos falta resolver un problema en este programa, ya que la adición de hojas no respeta el orden de los meses. Para que la nueva
hoja se agregue en última posición, y así conservar el orden natural de los meses, vamos a sustituir la
cifra 1 del parámetro After:=Sheets(1) por la variable Mi_Mes. De esta forma, cada nueva hoja se agregará en
última posición.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 3-
Y, para que la primera letra de cada mes esté en mayúscula, vamos a poner la función StrConv:
Sub Adición_Hoja()
Dim Mi_Mes As
Long
For Mi_Mes = 2 To 12
Sheets("Enero").Copy After:=SheetMsi(_Mes - 1)
ActiveSheet.Name = StrConv(MonthName(Mi_Mes, False), _
vbProperCase)
Next
End Sub
Puede descargar el código completo de este ejemplo, el archivo correspondiente se llama Ejemplo 12E4b.
- 4- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Calcular la diferencia entre dos fechas
Una de las principales dificultades de los cálculos en las fechas es la resta de dos fechas ya que hay que tener en cuenta
la fecha no a partir del primer día del mes, sino a partir del día indicado. Por ejemplo, entre el 31/12/2012 y el
01/01/2013 solo hay un día de diferencia y, sin embargo, ha cambiado el valor del mes así como el del año.
Afortunadamente, existe una función que soluciona este problema. En Excel, se trata de la función SIFECHA y en VBA, de
la función Datediff (en español en Excel y en inglés en VBA), y un funcionamiento diferente para las dos
instrucciones.
SIFECHA(Fecha1;Fecha2;parámetro)
La función SIFECHA requiere dos fechas (Fecha1 anterior a Fecha2) y un parámetro que concretará el tipo de
diferencia que queremos devolver entre las dos fechas.
Parámetro Resultado
"md" diferencia en días, una vez restados los años y los meses
Parámetro Resultado
"y" 1
"m" 19
"d" 600
"ym" 7
"yd" 235
"md" 23
En la función de VBA, el parámetro se coloca antes de la fecha y en este caso, la Fecha1 no tiene porqué ser anterior a la
Fecha2. El número de parámetros es mucho más importante como muestra la tabla siguiente, pero los resultados entre las dos
funciones son totalmente diferentes:
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Parámetro Resultado
yyyy Año
q Trimestre
m Mes
d Día
w Día de la semana
h Hora
n Minuto
s Segundo
Esta función no sabe gestionar rupturas de meses y de fechas. Por ejemplo, la diferencia en número de años entre el
31/12/2012 y el 01/01/2013 es igual a 1 (lo cual es obviamente falso).
Como la función SIFECHA de Excel es una función oculta, no es posible llamarla con la instrucción
Application.WorksheetFunction. La solución reside en la utilización de la instrucción Evaluate.
Evaluate(Texto)
La instrucción Evaluate permite integrar una función de Excel en VBA, esta función debe escribirse entre comillas. Por
consiguiente, podemos integrar la función SIFECHA de este modo:
Cells(1, 3) = Evaluate("=sifecha(A1,B1,""ym"")")
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Funciones de semanas
A diferencia de Excel, existen muy pocas funciones relacionadas con las semanas en VBA. De hecho, solo hay una.
WEEKDAY(Fecha,
parámetros)
La función WEEKDAY devuelve un valor entre 1 y 7 correspondiente al día de la semana. El parámetro permite
concretar cuál es el primer día de la semana. Por defecto, el primer día de la semana es el domingo, pero puede forzar
el día con uno de los otros seis días de la semana.
Para que el lunes se considere el primer día de la semana, agregue el parámetro vbMonday.
No existe ninguna función interna para devolver el número de días laborables entre dos fechas. Sin embargo, puede crear
usted mismo esta función utilizando la función WEEKDAY.
Basta con contar el número de días entre dos fechas excluyendo del contador los sábados y los domingos. Como una
fecha es un número, es posible integrar directamente las fechas en la instrucción FOR ... NEXT.
3. Número de semana
Del mismo modo, no existe una función que devuelva el número de semana de una fecha. Podría verse tentado a crear una
función que divida el número de días entre 7, pero las cosas no son tan sencillas...
Existe una diferencia en la contabilización de los números de las semanas entre Europa y Norteamérica. En
Norteamérica (Estados Unidos y Canadá), la semana 1 empieza en el primer día del año, aunque sea domingo. En Europa, la
numeración de las semanas se rige por la norma ISO 8601. La regla de numeración es más compleja, pero en la mayoría de
los casos, la semana n°1 contiene al menos 4 días. Si el mes de enero empieza un viernes, un sábado o un domingo, esta semana
no se considerará la semana 1.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
D = Int(D)
ºNSEM = DateSerial(Year(D + (8 - WeekDay(D)) Mod 7 - 3), 1, 1)
ºNSEM = ((D - NºSEM - 3 + (WeekDay(NºSEM) + 1) Mod 7)) \ 7 + 1
End Function
4. Días festivos
Los días festivos son siempre días particulares en los cálculos de fechas. Estos son o bien fijos (como el 1 de enero, el 25
de diciembre, etc.) o bien variables (como el domingo de Pascua); del domingo de Pascua depende el día de la Ascensión
(Pascua + 39) y el Pentecostés (Pascua + 49). Por lo tanto, es necesario determinar el "domingo de Pascua" que
corresponde al primer domingo siguiente (o cae el mismo día que) el día de la primera luna llena tras el equinoccio de
primavera (el 21 de marzo).
A partir de ahí, mediante el siguiente test puede determinar si la fecha que pasa como parámetro de la función es un día
festivo o no.
También puede incluir esta función en la función del número de días laborables, para descontar también de su bucle los días
festivos.
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Next
End Function
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 3-
Introducción
El soporte de su programa es un libro de Excel. Puede recuperar la información o copiar datos contenidos en este. Un libro
también está compuesto por hojas de cálculo que puede manipular, borrar, renombrar, etc.
En los capítulos anteriores hemos explotado los elementos más importantes de un libro: las celdas (Cells), los rangos
de celdas ( Range), las hojas (Sheets) y los libros (Workbooks).
En este capítulo vamos a ver cómo manipular los libros, abrirlos, cerrarlos, guardarlos y también cómo modificar las
propiedades de un libro (Nombre, Título, Comentario, etc.).
También veremos cómo utilizar VBA para trabajar directamente en Excel para evitar los mensajes de alerta, bloquear la
actualización de una hoja, etc. Las posibilidades son múltiples.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Manipulación de los libros
Desde un programa VBA, puede realizar todas las manipulaciones comunes en los archivos como abrir, cerrar,
guardar. Todos estos comandos son propiedades del objeto Workbooks.
ActiveWorkbook .Propiedades
ActiveWorkbook representa el libro activo. Cuando un programa abre varios libros, el libro activo es el último que se
ha abierto. Si desea trabajar en un libro específico, es aconsejable utilizar el objeto Workbooks (nombre del
archivo) para evitar que su programa se ejecute en el libro equivocado.
Con la instrucción Workbooks, el nombre del archivo debe tener obligatoriamente una extensión (xlsx, xlsm, etc.).
Atención: si utiliza el objeto Workbooks (nombre del archivo), su archivo deberá estar ya abierto o corre el riesgo de
generar una anomalía.
2. Abrir un libro
Para abrir un libro, basta con que añada el método Open al objeto Workbooks y que especifique la ruta de acceso y el
nombre del archivo (con su extensión). Puede escribir la información "literalmente" o con variables.
Workbooks.Open "C:\Documentos\Mi_archivo.xlsx"
’o
Workbooks.Open Ruta & Archivo
Si trabaja con variables, preste atención a no olvidar el carácter "\" entre la ruta de acceso y el nombre del archivo.
Utilice la depuración para verificar si la escritura Ruta + Archivo es en efecto una ruta de acceso existente.
Tras la instrucción Open, el libro que se acaba de abrir se convierte en el libro activo.
3. Cerrar un libro
El método Close cierra el archivo especificado. También puede utilizar el objeto ActiveWorkbook.Close para cerrar el
libro activo, pero puede ser un método peligroso si cerrase el libro que contiene el programa en ejecución.
Workbooks("Libro1.xlsx").Close
’o
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Workbooks(Nombre_Libro).Close ’ Aquí Nombre_Libro = "Libro1.xlsx"
’o
Workbooks(Nombre_Libro & ".xlsx").Close ’ Aquí Nombre_Libro="Libro1"
Al igual que al abrirlo, al cerrar un libro específico es obligatorio precisar la instrucción (xlsx, xlsm, etc.)
Si el archivo se ha modificado durante la ejecución del programa, automáticamente aparecerá un cuadro de diálogo que le
invita a guardar su documento, a menos que haya especificado mediante el parámetro SaveChanges si las
modificaciones deben guardarse (True) o no (False).
Workbooks("Libro1.xlsx").Close SaveChanges:=True
4. Guardar un libro
El método Save guarda su documento sin que usted tenga que confirmarlo .
Workbooks("Libro1.xlsx").Save
’o
ActiveWorkbook.Save ’Guardar el libro activo
Workbooks("Libro1.xls").SaveAs Filename:="España.xlsx"
’o
ActiveWorkbook.SaveAs "España.xlsx"
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Las propiedades de un libro
Muy a menudo, las propiedades de un libro contienen información recogida al guardarlo anteriormente (Autor, Fecha de
modificación, Nombre de la empresa, etc.).
Puede cambiar esas propiedades seleccionando el menú Archivo Propiedades (Excel 2003) o el Botón Office
Preparar Propiedades (en la versión 2007), o en la pestaña Archivo Información Mostrar todas las
propiedades (desde la versión Excel 2010).
Por ejemplo, puede manipular las siguientes propiedades en su libro, concretando cada vez el nombre de las propiedades:
With
ActiveWorkbook
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
.BuiltinDocumentProperties("Title") = Mi_nombre
.BuiltinDocumentProperties("Subject") = "Test_propiedades"
.BuiltinDocumentProperties("Author") = Mi_nombre
.BuiltinDocumentProperties("Keywords") = Variable_4
.BuiltinDocumentProperties("Comments") = Variable_5
.BuiltinDocumentProperties("Template") = Variable_6
.BuiltinDocumentProperties("Last author") = Variable_7
.BuiltinDocumentProperties("Company") = Variable_8
End With
Pero no es necesario concretar el nombre de las propiedades. Puede construir un bucle mediante la instrucción For Each
para recorrer todas las propiedades de un libro utilizando la colección de objetos
BuiltinDocumentProperties.
El siguiente código le permite recuperar todas las propiedades de su libro y mostrar cada una de ellas en una celda:
Sub Recuperación_de_las_propiedades()
Dim i_var As Long
Dim Prop As Object
On Error Resume Next
i_var = 1
For Each Prop In ActiveWorkbook.BuiltinDocumentProperties
Cells(i_var, 1) = Prop.Name
Cells(i_var, 2) = Prop.Value i_var
= i_var + 1
Next
End Sub
Estamos obligados a añadir la instrucción On Error Resume Next (ver el capítulo Gestión de errores) para no detener
el programa en el caso de que una propiedad no tuviera valor.
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Interactuar con la aplicación Excel
DoEvents
Cuando un programa se está ejecutando, ya no se puede actuar en su aplicación hasta que el programa acabe. Sin
embargo, puede pedir a Excel que "transfiera la ejecución" al sistema de explotación gracias a la instrucción
DoEvents.
Cada vez que el programa pase por esta instrucción, le indica a su ordenador que es prioritario con respecto a la
ejecución del programa. Así, puede, por ejemplo, volver a Excel y manipular el libro durante la ejecución de la macro
(copiando una celda, por ejemplo).
Calculate
La instrucción Calculate es importante ya que permite forzar el recálculo de una hoja de cálculo. Es muy útil si
necesita mostrar un cronómetro, por ejemplo, y gestionar la actualización (véase el ejemplo que se propone en el
capítulo Iniciar un programa de varias maneras Inicio mediante un botón u otro objeto) o incluso para comprobar
que se han actualizado todas las fórmulas del libro.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
El objeto Application
Excel es en sí mismo un objeto, como una celda o una hoja de cálculo, con sus propiedades y sus métodos. El objeto
Application tiene vinculadas no menos de 305 propiedades, métodos y eventos. Solo estudiaremos las principales, pero
si desea conocer todas las propiedades de este objeto, puede consultar la siguiente dirección:
https://msdn.microsoft.com/eses/library/office/ff198091.aspx
Si trabaja con Excel 2003 o inferior, algunas de esas funcionalidades no estarán disponibles.
1. ScreenUpdating
Esta propiedad permite bloquear la actualización de Excel durante la ejecución de un programa. Al utilizar esta
propiedad, ganará mucho tiempo en el tratamiento de su programa ya que bloquea la actualización de Excel. No olvide
reubicar el valor de esta propiedad a True antes de abandonar el programa.
2. DisplayAlerts
Esta propiedad impide que se muestren los mensajes de alerta (valor False), como por ejemplo la ventana de alerta que le
invita a guardar un libro o la que aparece cuando elimina una hoja.
Al final del programa, es imprescindible que vuelva a poner el valor en True para que Excel continúe mostrando los mensajes de
alerta de forma normal.
3. StatusBar/DisplayStatusBar
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
l StatusBar gestiona los mensajes en la barra de estado.
La propiedad StatusBar le permite visualizar los mensajes en la barra de estado. Así, puede, por ejemplo, seguir el
desarrollo de su programa escribiendo el último número de fila tratada. La propiedad StatusBar es preferible a
MsgBox ya que la visualización de un mensaje con la instrucción MsgBox bloquea la ejecución de programa.
Para borrar sus mensajes personales en la barra de estado, debe colocar el valor False en la propiedad StatusBar:
Excel cuenta con más de 400 funciones de cálculo; 471 en la versión Office 365 de Excel para ser precisos. Algunas de
ellas han sido objeto de desarrollos optimizados por parte de universidades especializadas en estadística como para los
cálculos de desviaciones estándar y de varianza, entre otros.
De igual modo, es muy recomendable usar las funciones de cálculo de Excel en sus programas y recuperar
fácilmente el resultado en una variable antes que tener reescribir usted mismo las funciones de cálculo.
La llamada a funciones de cálculo se obtiene con la propiedad WorksheetFunction seguida del nombre de la función
en inglés. Si lo escribe en español, el VBA no será capaz de interpretarlo. A continuación, deberá pasar los parámetros
que su función espera, exactamente de la misma manera que si usara la función en una hoja de cálculo.
Por ejemplo, si desea calcular la suma de los valores de su rango de celdas A1:A5 escribirá lo siguiente:
Sub Fonction_Cálculo()
Dim Result_Suma As Double
Result_ Suma = Application.WorksheetFunction.Sum(Range("A1:A5")) End
Sub
Pero algunas funciones pueden llamarse directamente. Es el caso de la función Match (equivalente de la función de cálculo
EQUIV) y de la función Index.
b. La función Match
La función Match permite recuperar el valor de la fila donde se sitúa el valor buscado. Por ejemplo, en el ejemplo
siguiente, se desea conocer el número de fila donde se encuentra el valor FFF.
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Sub Fonction_Cálculo()
Dim Núm_Fila As Long
Núm_Fila = Application.Match("FFF", Range("A1:A10"),
0) MsgBox "El número de la fila es: " & Núm_Fila
End Sub
c. La función Index
Por último, la función Index puede también escribirse directamente después de la instrucción Application. La
función Index permite encontrar el valor de una celda que se encuentra en la intersección entre una fila y una
columna.
Pero otro uso de la función Index permite permutar los datos de las columnas de una tabla en una sola
instrucción.
Y desea permutar las columnas entre ellas. En lugar de hacer una sucesión de operaciones de copiar/pegar, la siguiente
función permite llevar a cabo las manipulaciones de reordenación de acuerdo con las posiciones inscritas en la tabla al final
(Array).
Atención, para usar este procedimiento, deberá seleccionar los datos previamente a partir de la instrucción
UsedRange.
Sub Rearrange()
With ActiveSheet.UsedRange
.Value = Application.Index(.Value, .Worksheet.Evaluate("ROW(" & _
.Columns(1).Address & ")"), Array(7, 2, 4, 1, 6, 5, 3))
End With
End Sub
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 3-
Y el resultado de la permutación pasa a ser:
Es posible solicitar a un programa que «espere» unos instantes antes de ejecutar la siguiente acción. Esto podría
ocurrir para acceder a datos en la Web o en un servidor remoto para los cuales el tiempo de espera es variable. Por tanto,
para evitar que una instrucción se ejecute antes de haber recibido datos, es posible imponer al programa que
espere durante un plazo de tiempo que se fijará usando la propiedad Wait.
Pero tenga cuidado, la propiedad Wait esperará recibir un valor en el futuro. Si desea que el programa se detenga
durante diez segundos, tendrá que decirle que volverá a arrancar diez segundos después del tiempo actual. Esto se escribe
de la manera siguiente:
Sub Test_Wait()
Nueva_Hora = Hour(Now())
Nuevo_Minuto = Minuto(Now())
Nuevo_Segundo = Second(Now()) + 10
Tiempo_Espera = TimeSerial(Nueva_Hora, Nuevo_Minuto , _
Nuevo_ Segundo)
Application.Wait Tiempo_Espera
End Sub
También puede escribir la hora exacta en que el programa se pondrá de nuevo en marcha de la siguiente manera:
Application.Wait ("20:20:00")
La propiedad GetOpenFilename permite mostrar el cuadro de diálogo Abrir. La utilizará para permitir a los usuarios escoger el
archivo que desean abrir.
Pero esta propiedad no abre el archivo, solo recupera la ruta de acceso y el nombre del archivo seleccionado . A
continuación, tiene que utilizar el método Open para abrir el archivo.
- 4- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Puede añadir a esta propiedad el tipo de archivo. De este modo, solo los archivos que tengan esta extensión aparecerán en
el cuadro de diálogo.
Del mismo modo, con la propiedad GetSaveAsFilename puede mostrar el cuadro de diálogo Guardar como para
recuperar el nombre del archivo que el usuario ha elegido. Empleará esta propiedad para localizar el nombre con el
que se guardará el libro y después, guardará el libro con el método SaveAs.
Para imponer un formato al archivo, puede indicar como parámetro el tipo de extensión con la que se guardará el
archivo:
Nombre_Archivo = Application.GetSaveAsFilename( _
fileFilter:="Archivo Excel (*.xls),
*.xls") ActiveWorkbook.SaveAs Nombre_Archivo
Si define una zona de impresión específica al ejecutar el programa, el tratamiento se verá enormemente ralentizado. Para
evitarlo, hay que cortar la conexión con la impresora durante el tiempo en que se define la configuración de la
página ( PageSetup).
Cuando lleva a cabo una operación de copiarpagar en Excel, una vez efectuado el pegado, la celda de origen aparece
siempre rodeada de una línea de puntos que indica que la acción de pegado se encuentra todavía activa. En programación
ocurre lo mismo.
Al final de la operación de pegado, para indicar que la celda de origen debe perder su carácter de elemento
potencialmente reutilizable para ser pegada de nuevo, escriba la siguiente instrucción:
Application.CutCopyMode = False
Durante la ejecución de un programa es posible hacer una llamada al código contenido en otro libro de Excel. Si tiene un
libro con un código muy específico como para diseñar un gráfico, por ejemplo, antes de importar el código al libro activo, es
posible llamarlo usando esta instrucción:
Application.Run "C:\MisDocumentos\MiLibro.xlsm!Modulo1.Sub_Llamada"
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 5-
Al igual que para abrir libros, es preciso indicar la ruta y el nombre del libro con su extensión, pero también hay que
añadir un signo de exclamación seguido del nombre del Módulo en el que se encuentra el procedimiento que va a
ejecutar.
- 6- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Introducción
En el capítulo Trabajar en un libro Excel, hemos visto cómo abrir, cerrar y guardar libros. Ahora vamos a ver otras
funciones para trabajar con archivos, pero desde una carpeta (renombrar, copiar, suprimir archivos, etc.). Veremos cómo
recorrer todos los archivos de un directorio y cómo filtrarlos según su extensión.
También veremos cómo recuperar el contenido de una celda sin abrir el libro correspondiente y cómo visualizar un
Explorador de carpetas.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Operación con archivos
Las siguientes funciones permitirán hacer operaciones con todo tipo de archivos. Por consiguiente, podrá utilizar un
programa VBA como Explorador de carpetas Windows para hacer todo tipo de operaciones en los archivos de su
ordenador.
1. Copiar un archivo
Puede copiar un archivo de un directorio a otro, sea cual sea su extensión (texto, imagen, sonido, vídeo, etc.)
utilizando la instrucción FileCopy.
Archivo1 = "C:\Dir_1\Documento.txt"
Archivo2 = "C:\Dir_2\Documento.txt"
FileCopy Archivo1, Archivo2
Esta instrucción no realiza ningún control en el nuevo nombre. Es importante que conserve el mismo tipo de
extensión entre el antiguo nombre y el nuevo. Además, si olvida precisar la extensión, el archivo será ilegible.
3. Mover un archivo
También puede usar la función Name para mover un archivo de un directorio a otro. Para hacerlo, bastará con indicar,
además del código anterior, el nombre de la ruta de inicio y el nombre de la ruta final sin cambiar esta vez el nombre del archivo.
Por ejemplo, para mover el archivo test.xlsx desde el escritorio hasta una subcarpeta, escribirá:
SubDesplazamiento_Archivo()
Dim Ruta_Inicio As String Dim
Ruta_Final As String
Ruta_Inicio = "C:\Users\Escritorio\"
Ruta_Final = "C:\Users\ Escritorio\Nueva Carpeta\"
Name Ruta_Inicio & "test.xlsx" As Ruta_Final & "test.xlsx" End Sub
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Si cambia también el nombre del archivo, no solo desplazará el archivo, sino que también le cambiará el nombre en la
misma línea de código.
4. Eliminar un archivo
Último punto esencial, la supresión. Aquí, no hay objeto que deba especificarse ni método que se deba aplicar, sino solo
una instrucción a la que llamar, Kill.
Kill "C:\Documentos\Libro4.xlsx"
’o
Kill Ruta & Archivo
FileDateTime(Ruta&Archivo)
Para recuperar la fecha o la hora, puede utilizar las funciones de texto para realizar un recorte:
El recorte de la fecha se interpretará como una cadena de caracteres y no como un dato de tipo fecha. El resultado en la celda
A1 se alineará a la izquierda de la celda, señal de que se trata de texto y no de un dato numérico. Para
convertir este resultado en fecha, hay que emplear la instrucción CDate.
FileLen(Ruta&Archivo)
Para convertir el resultado en kilobytes, debe dividir el resultado entre 1024. La siguiente tabla presenta el valor del
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
divisor para obtener la conversión en las distintas unidades de medida:
Pentabyte (PB) 1024 TB 1024 5 = 1 125 899 906 842 624 bytes
Dir(Ruta)
La instrucción Dir devuelve un nombre que representa el nombre del archivo. Sin otro parámetro que la ruta, Dir
devuelve el primer archivo encontrado sea cual sea su extensión. Para restringir su búsqueda, puede especificar, además
de la ruta, el tipo de archivo que busca:
Del mismo modo, puede precisar una parte del nombre para filtrar más su búsqueda.
Atención, la instrucción Dir recupera los nombres de los archivos sin ningún orden predefinido.
Podrá entonces verificar si el archivo existe en el directorio haciendo este simple test:
Puede escribir el mismo test, pero dentro de una función. De esta forma podrá llamar al test desde cualquier parte del código.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 3-
Existe_ Archivo = True
End If
End Function
La función se declara como Boolean, ya que solo puede devolver dos valores Verdadero o Falso (el archive existe o no).
Para llamar a esta función, basta con escribir el nombre de la función en el procedimiento de llamada (la función
espera dos parámetros, por tanto se deberá llamar a la función transmitiendo los dos parámetros esperados).
- 4- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Operaciones con los directorios
También puede realizar tareas a nivel de directorios, renombrarlos o duplicarlos, por ejemplo. También puede recorrer
uno a uno todos los archivos de un directorio.
ChDir Ruta
Como hemos comprobado a menudo, para la apertura o escritura de archivos, es importante precisar la ruta de acceso.
Pero si siempre trabaja en el mismo directorio, puede especificar a su programa la ruta que debe seguir durante toda la
ejecución del programa.
Así, no estará obligado a recordar la ruta de acceso al directorio en las instrucciones de apertura, guardado, etc.
2. Crear un directorio
MkDir Nuevo_Directorio
Esta instrucción crea un nuevo directorio en el directorio actual. Pero también puede especificar toda o parte de la ruta
de acceso:
MkDir "Archivo"
’o
MkDir "C:\Documentos\Archivo"
3. Eliminar un directorio
RmDir Nombre_Directorio
Esta instrucción elimina un directorio. Es absolutamente necesario que el directorio esté vacío de todo archivo para poder
suprimirlo.
RmDir "Archivo"
’o
RmDir "C:\Documentos\Archivo"
Antes de crear un directorio es indispensable comprobar si el nombre de ese nuevo directorio existe previamente. Por otro
lado, no se puede eliminar un directorio inexistente. Por esto es por lo que se recomienda utilizar la función
siguiente para comprobar si un directorio está o no presente en una carpeta.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Function ArchivoDirExiste(Ruta_A_Probar As String) As Boolean
On Error GoTo SalidaPgm
ArchivoDirExiste = False
If Not Dir(Ruta_A_Probar, vbDirectory) = vbNullString Then
ArchivoDirExiste = True
End If
SalidaPgm:
On Error GoTo 0
End Function
Para llamar a esta función y verificar la existencia de un directorio, bastará con comprobar si la función devuelve
Verdadero o Falso. Por ejemplo, es posible escribir:
Sub TestDirExiste()
If ArchivoDirExiste ("C:\Mis Documentos") Then
MsgBox "El directorio existe"
Else
La instrucción Dir también permite hacer un bucle para hacer una lista de todos los archivos de un directorio. Para ello,
la instrucción Dir se emplea de dos formas:
Así, la instrucción Dir se ubicará en otro archivo del mismo tipo y, cuando se hayan recorrido todos los archivos, esta
devolverá una cadena vacía.
Por ejemplo, en una carpeta determinada, deseamos añadir al principio de todos los nombres de archivos Excel la
palabra "Informe ".
Sub Bucle_Archivo
Dim Nombre_Archivo As String
Nombre_Archivo = Dir("C:\Mis Documentos\*.xlsx")
While Nombre_Archivo <> ""
Name Nombre_Archivo As "Inform-e " & Nombre_Archivo
Nombre_Archivo D=ir
Wend
End Sub
Si solo desea recuperar los nombres de subdirectorios del nivel inferior, puede añadir un parámetro a la instrucción
Dir:
Dir(Ruta, parámetro)
vbReadOnly Especifica los archivos accesibles solo en modo lectura, así como los archivos sin atributos.
vbHidden Especifica los archivos ocultos, así como los archivos sin atributos.
vbSystem Especifica los archivos del sistema, así como los archivos sin atributos.
vbVolume Especifica el nombre de volumen; si se especifica otro atributo, la constante vbVolume se ignora.
vbDirectory Especifica las carpetas, así como los archivos sin atributos.
Para recuperar los nombres de los directorios, hay que utilizar el parámetro vbDirectory. Pero atención, recuperará
los nombres de los directorios, pero también los nombres de los archivos.
También recuperará los indicadores del directorio actual (simbolizado por un punto) y del directorio superior
(simbolizado por dos puntos). Es interesante hacer un test para evitar tratar estos dos casos en su programa:
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
If Nombre_Archivo <> "." And Nombre_Archivo <> ".."
Then
Instrucciones
End
If
La instrucción GetAttr (Variable_Nombre_Archivo) devuelve los atributos de los archivos. Esta instrucción es muy
útil para hacer un test que controle si el elemento seleccionado es un archivo o un directorio.
También puede crear un procedimiento que almacene en una tabla todos los subdirectorios de una carpeta
cualquiera. El siguiente código puede aplicarse a cualquier carpeta ya que la ruta del directorio analizado (Mypath) se
transmite como parámetro del procedimiento.
End If
End If
MyName = Dir
Loop
End Sub
Hemos visto que la función Dir recorre todos los archivos del directorio y también los directorios de un solo nivel inferior,
pero nada más. Para poder leer todos los subdirectorios sin restricciones, es preciso hacer un bucle recursivo.
Un bucle recursivo es un bucle o procedimiento que se llama a sí mismo. El riesgo de los bucles de ese tipo es que el
procedimiento se llama hasta el infinito sin detenerse por lo que será indispensable prever una condición de salida para el bucle.
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
A modo de recordatorio, si se da el caso de que su programa entre en bucle hasta el infinito, es posible interrumpir la ejecución
pulsando las teclas [Ctrl][Pausa].
Pero creando bucles recursivos podrá crear programas que ofrezcan nuevas posibilidades de programación.
Por ejemplo, para barrer todos los subdirectorios de una carpeta determinada, puede usar el código que se basa en la
misma funcionalidad que la utilizada para buscar archivos Windows, el objeto FileSearchObject. Cada vez
que se encuentra una carpeta, la ruta se almacena en una tabla en la memoria y también en la primera columna del libro.
Encontrará el mismo código en el archivo Ejemplo 14D.
’Declaration
Public oFSO, oFld, oSubFolder
Public Tab_Dir() As String ’Tabla en memoria donde se almacenarán los
nombres de los archivos
Public i As Long
’====================================================================
’Función recursiva para encontrar todos los subdirectorios
’con el objeto FileSystemObject
’====================================================================
Sub RecorridoDirT()
’ Llamada al objeto FileSystemObject
Set oFSO = CreateObject("Scripting.FileSystemObject")
i = 0
’ Llamada a la función recursiva
Call RecorridoDir("C:\
Users") End Sub
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 3-
End If
End If Exit
Sub Tratamiento
error:
Debug.Print Err.Number & " " & Err.Description
Resume Next
End Sub
- 4- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Recuperar los datos sin abrir un libro
Si realiza un programa que abra y cierre libros para recuperar valores, comprobará que este tipo de tratamiento es lento
ya que estas operaciones son muy costosas en términos de memoria.
Para evitar saturar la memoria de su ordenador por esas múltiples operaciones de apertura y cierre de archivos,
usaremos astutamente la posibilidad que ofrece Excel de leer el contenido de una celda de un libro cerrado.
En una hoja de cálculo, tiene una celda que apunta a la celda B10 de un libro que está cerrado. Como fórmula tendrá algo
similar a esto: =’C:\Users\MisDocumentos\[Libro1.xlsx]Hoja1’!$B$10
Ahora, en programación trasladaremos esta escritura teniendo cuidado de respetar todos los símbolos esperados por la
fórmula.
Para asegurarnos de no cometer ningún error de sintaxis, pondremos cada uno de los elementos esperados (ruta, nombre
del libro, nombre de la hoja y dirección de la celda) en distintas variables. De esta manera resultará más fácil cambiar
cualquiera de las variables en función de las necesidades del programa.
Sub Enlace_Externo()
Dim Ruta As String
im MiLibro As String
Dim MiHoja As String
Dim MiCel As String
Dim MiFórmula As String
Ruta = "C:\Users\MisDocumentos\"
MiLibro = "Libro1.xlsx"
MiHoja = "Hoja1"
MiCel = Cel(2, 10).Address
MiFórmula= "’=" & Ruta & "[" & MiLibro & "]" & MiHoja & _
"’!" & MiCel
Range("A1") = MiFórmula
End
Sub
La instrucción Address es obligatoria ya que es la referencia de la celda que vamos a recuperar y no el contenido de la
celda.
A continuación, es fundamental conservar todos los símbolos de la fórmula como pueden ser los corchetes, que expresan el
nombre del archivo, el signo de exclamación que separa el nombre del archivo de la dirección de la celda y los apóstrofos que abren
y cierran la ruta de acceso, el nombre del archivo y el nombre de la hoja de cálculo.
Como todos los componentes son variables, ahora resultará sencillo efectuar bucles tanto sobre el nombre de los archivos (con
la instrucción Dir), como sobre el nombre de las hojas (For Each) o incluso sobre las filas o columnas
de las celdas.
Al final del código que ha construido las referencias externas, se puede no conservar el enlace y conservar solo los valores
copiando y pegando la selección.
Cells(5, 4).Copy
Cells(5, 4).PasteSpecial xlPasteValues
Application.CutCopyMode = False
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Seleccionar un directorioI
Para poder seleccionar un directorio de trabajo mientras el programa se está ejecutando deberá utilizar la función
FileDialog, pero esta función no puede usarse sola. Es preciso asociarla a la función Application para poder
llamarla.
Sub Abrir_Cuadro_Dialogo()
Application.FileDialog(msoFileDialoFgolderPicker).Show
End Sub
Pero mostrar el cuadro de diálogo para seleccionar un directorio no es suficiente, después es preciso recuperar el nombre
del directorio seleccionado. Para ello será preciso escribir la siguiente línea de código:
Sub Dir_Selection ()
Dim Dir As String
Application.FileDialog(msoFileDialogFolderPicker).Show
Dir = Application.FileDialog(msoFileDialogFolderPicker).SelectedItems(1)
MsgBox Dir
End Sub
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Seleccionar un archivo
Continuando con la instrucción FileDialog, también es posible seleccionar uno o varios archivos. Para ello deberá
modificarse el parámetro entre paréntesis. Por ejemplo, para seleccionar un archivo, escribirá:
Sub Selection_Un_Archivo()
Application.FileDialog(msoFileDialogFilePicker).AllowMultiSelect = False
Application.FileDialog(msoFileDialogFilePicker).Show
MsgBox Application.FileDialog(msoFileDialogFilePicker).SelectedItems(1) End
Sub
Para seleccionar varios archivos dentro del mismo directorio, deberá posicionar el indicador de multiselección en True y
después hacer un bucle para recuperar los nombres de los archivos seleccionados.
Después, lo más sencillo para tratar todos los archivos es almacenar sus nombres en una tabla en memoria (vea el
capítulo Optimización Las tablas en memoria para comprender cómo trabajar con tablas en memoria).
Sub Selection_X_Archivos()
Dim Tab_Nombre_Archivo() As String
Dim Index_ Archivo As Long
Application.FileDialog(msoFileDialogFilePicker).AllowMultiSelect = True
Application.FileDialog(msoFileDialogFilePicker).Show
For Index_Archivo = 1 To Application.FileDialog(msoFileDialogFilePicker). _
SelectedItems.Count
ReDim Preserve Tab_Nombre_ Archivo (Index_ Archiv-o 1)
Tab_Nombre_ Archivo (Index_ Archiv-o 1) = _
Application.FileDialog(msoFileDialogFilePicker).SelectedItems(Index_ Archivo) Next
End Sub
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Introducción
La optimización de un programa significa que vamos a mejorar la velocidad de ejecución del código, evidentemente, sin
cambiar el resultado final.
Este aspecto de la programación es muy importante. Trabajando como asesor, he tenido que reescribir por completo
programas que se ejecutaban en más de cuarenta minutos y he conseguido reducir el tiempo a apenas unos
segundos (quince, para ser exactos).
A continuación, encontrará muchas técnicas que permiten mejorar la rapidez de ejecución del código.
l Cómo devolver en una sola instrucción el número de líneas de una columna sin tener que crear un bucle para contabilizar
todas las filas.
l La utilización de tablas para trabajar con datos almacenados en la memoria. En este capítulo profundizaremos en esta técnica y
presentaremos funciones específicas del uso de las tablas.
Todas estas técnicas permiten reducir significativamente el tiempo de tratamiento. Pero también hay otros medios
para mejorar la velocidad de ejecución, como la búsqueda de elementos en una hoja de cálculo sin pasar por bucles.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Instrucciones de búsqueda
Es posible realizar una búsqueda en un rango de celdas sin tener que recorrer las líneas una por una con un bucle
hasta encontrar el elemento buscado. Así conseguimos ganar muchísimo tiempo.
1. El método FIND
Range.FIND(Elemento buscado)
Los objetos Range, Rows y Columns disponen del método FIND que permite buscar un valor. Por ejemplo, el
archivo Ejemplo 15B1 contiene una lista de nombres en la columna A; buscamos el apellido SMITH.
El resultado de un método FIND no es una variable, sino un Objeto. Por eso hay que definir la variable que devolverá el
resultado de una búsqueda con la instrucción Set.
Como el resultado es un objeto, hay un gran número de propiedades vinculadas al resultado de la búsqueda. Con la
herramienta Inspección, puede ver el conjunto de estas propiedades:
El valor del objeto no tiene realmente importancia ya que este será necesariamente igual al elemento buscado. Por el contrario,
puede recuperar las propiedades Row y Column para conocer el número de fila y el número de
columna en la que se ha encontrado el elemento buscado de la siguiente manera:
En caso de búsqueda infructuosa, la variable devolverá Nothing. Puede hacer un test con la instrucción Is Nothing
para saber si la búsqueda ha llegado al resultado o no:
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
If Nombre_ok Is Nothing Then
Instrucción si no encontrado
Else
Instrucción si sí encontrado
End If
Range.FindNext(Objeto)
Cuando la búsqueda haya llegado al resultado y desee buscar el mismo valor en el mismo rango de datos, puede utilizar
el método FindNext en un bucle. Este método debe tener como parámetro el nombre del objeto para poder continuar la
búsqueda.
Sin embargo, el método FindNext es incapaz de determinar el final de su lista de búsqueda: la búsqueda volverá al
principio y así, hasta el infinito . Para poder parar la búsqueda, antes de hacer el bucle, hay que recuperar el número de la
primera fila o la dirección de la primera celda que corresponda al elemento buscado. Cuando el valor de la fila sea otra vez
igual al valor de la primera fila de búsqueda, el bucle se detendrá.
Desde la página Información encontrará el código que encuentra todos los valores Smith en el archivo Ejemplo 15 B3.
De la misma forma, puede realizar una búsqueda en elementos anteriores utilizando el método FindPrevious.
4. Opciones de búsqueda
El método FIND corresponde en Excel al cuadro de diálogo Buscar. En VBA, todas las opciones de este cuadro de
diálogo se pueden configurar mediante las opciones del método FIND.
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Puede añadir a su búsqueda las siguientes opciones:
l After: precisa la celda tras la cual usted desea empezar la búsqueda. Esta corresponde a la posición de la celda activa cuando
una búsqueda se realiza a partir de la interfaz del usuario.
l LookIn: corresponde a la opción Mirar en: puede precisar la búsqueda en los valores (xlValue) o en las fórmulas
(xlFormulas).
l LookAt: indica si la búsqueda debe realizarse en toda la celda (xlWhole) o en una parte (xlPart).
l SearchOrder: indica el sentido de la búsqueda: por fila (xlByRows) o por columna (xlByColumns).
l SearchDirection: indica el sentido de la búsqueda: (xlNext) o (xlPrevious). Esta opción es rara ya que es un duplicado de
las instrucciones FindNext y FindPrevious.
l MatchByte: si ha instalado fuentes de caracteres codificados en 2 bytes (escritura vietnamita, china, etc.). Debe colocar esta
variable en True; False es el valor predeterminado.
Por ejemplo, para realizar una búsqueda en una parte de la celda, puede escribir la instrucción siguiente:
Por el contrario, una sola opción presente en el cuadro de diálogo no existe en parámetros en VBA: es la opción de búsqueda en
una sola hoja o en todo el libro.
Esta observación es importante ya que la búsqueda Find se hará siempre en función de la opción del cuadro de diálogo. Si la
opción está posicionada en el libro, la ejecución del código se hará sobre todo el libro, incluso si solo
quiere examinar una hoja.
Efectuar una búsqueda en una hoja de cálculo sirve a menudo para encontrar el número de la fila en que se encuentra el
valor buscado. Para devolver el número de fila, existen varios métodos:
El primero consiste en asociar la propiedad Row al resultado de la búsqueda. En este ejemplo, ponemos el código para
recuperar el número de fila en una función. De esta manera, si tuviera que buscar varias veces el número de la fila en el
programa, bastará con llamar a la función en lugar reescribir varias veces la misma instrucción de búsqueda.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 3-
Sub Programa()
MsgBox Encuentra_Fila("CCC")
End Sub
La segunda técnica para encontrar el número de fila del valor buscado no utiliza la función Find sino una propiedad de la
instrucción Application; la función Match.
Sub Find_Match()
Dim Encuentra_Núm_Fila As Long
Encuentra_Num_Fila = Application.Match("CCC", Columns("A"), 0)
MsgBox Encuentra_Num_Fila
End Sub
La propiedad Match se comporta exactamente como la función EQUIV de Excel. Los parámetros que se esperan son:
l El valor buscado
l El rango de búsqueda
- 4- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Las tablas en memoria
Trabajar con tablas siempre es un enfoque de programación que desconcierta. Muchos usuarios imaginan que los datos
están en alguna parte dentro del ordenador, invisibles, y que en caso de error será muy fácil encontrarlos. De
hecho, no es así.
Para los usuarios principiantes resulta muy tentador escribir parámetros temporales en una hoja de cálculo para leerlos
y reutilizarlos más tarde, ya que la actualización de los datos en la hoja de cálculo se puede visualizar fácilmente.
Esta técnica está lejos de resultar óptima, ya que cada vez que escribe un valor temporal en la celda de una hoja de
cálculo, también está recurriendo a la interfaz gráfica de Excel. Y usted sabe que la vista de filas, columnas y hojas
requiere mucha memoria.
Por tanto, para mejorar la ejecución de los programas, aconsejamos vivamente que almacene sus datos en tablas en
memoria durante el tiempo de ejecución del programa.
Una tabla de una dimensión es exactamente como si tuviera los datos en una sola columna del libro.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Vista de una tabla en memoria desde la depuradora
Para encontrar un valor desde una hoja de cálculo deberá indicar los valores, la fila y la columna. Por ejemplo, si desea
encontrar el valor número cuatro, escribirá:
Valor_Celda = Cells(4, 1)
Ahora, si interroga a una tabla en memoria, bastará con precisar el rango. La única diferencia con respecto a las
columnas es que es necesario quitar una unidad ya que las tablas almacenan los datos a partir del valor 0.
Valor_Tabla=Día_Sem(3)
En los bucles, para encontrar el valor "Sábado", es posible escribir la siguiente instrucción:
Dim i as Long i = 1
While Cells(i, 1) <> "Sábado"
Instructions
i = i + 1
Wend
i = 0
While Tab_Memoria(i)<> "Sábado"
Instructions
i = i + 1
Wend
Una vez más, esta noción parece compleja al principio, pero es muy simple de visualizar. Una tabla de dos
dimensiones es exactamente igual que la cuadrícula de una hoja de cálculo de Excel; consta de filas y columnas.
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Es cierto que imaginarse una tabla de dos dimensiones es desconcertante al principio, pero, de hecho, resulta muy fácil
recuperar las notas de un alumno haciendo variar el segundo índice de la tabla dentro de un bucle:
For i = 0 To 3
MsgBox " Valor de la nota " & i & " " & Notas_Alumnos(0, i)
Next
También es posible recuperar igual de fácilmente todas las notas de la segunda materia haciendo variar esta vez el
primer índice de la tabla:
For i = 0 To 5
MsgBox " Valor de la nota nota " & i & " " & Notas_Alumnos (i, 1)
Next
Pero también es posible introducir datos con la instrucción Array. Bastará con que escriba todos los datos que desee
separándolos con una coma.
Mi_Tabla = Array(" Lunes ", " Martes ", " Miércoles ")
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 3-
Esta técnica obliga a declarar la tabla como Variant.
Caso práctico: escribir todos los encabezados de columna en una sola línea de código
La instrucción Array permite también transferir diferentes valores a un rango de celdas. Por ejemplo, si tiene un
documento que empieza por las mismas descripciones de columnas, simplemente escribirá:
Range(" A1:D1 ") = Array(" Fecha ", " Cliente ", " Precio ", " Cantidad ")
También es posible cargar una tabla de dos dimensiones en memoria usando el símbolo de punto y coma para cambiar de
dimensión. Por ejemplo, si tenemos una tabla de cuatro filas y dos columnas, podemos cargar la tabla de la siguiente manera:
Sub Carga_2_Dimensiones()
Dim MiTabla As Variant
MiTabla = [{2,6;3,8;10,14;5-,1}]
End Sub
Muy a menudo, los datos que se quieren cargar en la tabla ya están recogidos en la hoja de cálculo. No obstante, en lugar de
elaborar un bucle para recoger los valores uno por uno en una tabla en memoria, un truco de Excel permite transferir todo el
rango de datos a una tabla.
- 4- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
La inserción de esos datos en una tabla se hace con una sola instrucción:
Sub Inserción_Tabla()
Dim Mi_Tabla As
Variant
Mi_Tabla = Range(" A1:A7
") End Sub
l La declaración de la variable se hace sin especificar el tamaño (sin paréntesis) y siempre como Variant.
l El resultado de esta técnica copia el contenido de la columna en una tabla de dos dimensiones (siempre).
l La tabla tampoco empieza en el valor 0 como hemos visto hasta ahora, sino en el valor 1.
Es posible transferir el contenido de un rango de celdas de varias filas y columnas a una tabla en memoria de la misma
manera:
Sub Inserción_Tabla ()
Dim Mi_Tabla As Variant
Mi_Tabla = Range(" A1:E7 ")
End Sub
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 5-
Este es el resultado:
Cuando trabaja con tablas de una o dos dimensiones, puede borrar fácilmente todos los datos sin necesidad de bucles
gracias a la instrucción Erase.
Erase Mi_Tabla
Como podrá comprobar, los parámetros que definen el tamaño de la tabla no se mencionan. De hecho, el inicio se realiza
en el conjunto de la tabla.
Cuando se trabaja con tablas se debe especificar su tamaño en las declaraciones. Por ejemplo:
Pero esto obliga a conocer previamente el tamaño máximo de las tablas y no siempre es así. Sin embargo, es posible
cambiar el tamaño de las tablas a una dimensión durante el tratamiento.
- 6- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Para redefinir el tamaño de una tabla de una dimensión se puede usar la instrucción ReDim.
Queremos, por ejemplo, crear una tabla que se corresponda con el número de filas no vacías. Recuperaremos el
número de filas con contenido de la columna A y usaremos este valor para establecer el tamaño de la tabla:
El valor 1 es necesario aquí para respetar que las tablas empiezan siempre en la posición 0.
Se puede, sin embargo, especificar que una tabla empieza en la posición 1 escribiendo al principio del módulo la
siguiente instrucción:
Option Base 1
Atención, el uso de la instrucción ReDim sola inicia obligatoriamente todos los datos almacenados previamente en la tabla.
Para conservar los datos previamente grabados, deberá hacer que a la instrucción ReDim le siga la instrucción
Preserve.
De esta manera, podrá variar el tamaño de la tabla a lo largo del programa a medida que vaya agregándole datos sin
perder por ello los datos almacenados previamente.
Al usar una tabla, puede conocer fácilmente su tamaño gracias a las instrucciones LBound (posición del primer
elemento) y UBound (posición del último elemento).
LBound(Tabla, dimensión)
UBound(Tabla, dimensión)
Así, para realizar un bucle en una tabla cuya dimensión no conoce, basta con escribir esta instrucción para hacer un bucle desde
el primer elemento hasta el último. Este código funciona en todos los ejemplos de tablas de una dimensión.
Si la tabla tiene varios tamaños, deberá concretar mediante el argumento Dimension, en qué dimensión desea
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 7-
devolver el elemento por el que empieza su tabla.
Por ejemplo:
... ...
Cuando crea una tabla en la memoria, puede realizar fácilmente una búsqueda en los elementos que contiene sin tener
que hacer un bucle en cada elemento uno por uno. Para realizar esta búsqueda, debe utilizar la función
Filter.
l El argumento include precisa si su búsqueda debe contener (True) o no contener (False) el elemento de búsqueda.
El resultado devuelto por la función es en sí mismo una tabla. En ese caso, tendrá que crear un bucle para hacer
aparecer todos los resultados encontrados.
Para declarar una tabla cuya dimensión no conoce previamente, deberá hacer seguir el nombre de su variable por parámetros
abiertos y cerrados sin valor.
Sub Búsqueda_En_Tabla()
Dim Mi_Tabla(3) As String
Dim Tab_Resultado() As String
Dim i As Long
Mi_Tabla(0) = "uno"
Mi_Tabla(1) = "dos"
Mi_Tabla(2) = "tres"
Mi_Tabla(3) = "cuatro"
- 8- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Ahora, si buscamos el valor "s", el programa devolverá en A1 "dos" y en A2, "tres".
Sub Búsqueda_En_Tabla()
Dim Mi_Tabla(3) As String
Dim Tab_Resultado() As String
Dim i As Long
Mi_Tabla(0) = "uno"
Mi_Tabla(1) = "dos"
Mi_Tabla(2) = "tres"
Mi_Tabla(3) = "cuatro"
Tab_Resultado = Filter(Mi_Tabla, "d"F,alse)
Para llevar a cabo la búsqueda de una palabra exacta deberemos añadir un test con el fin de evitar que nos
devuelva palabras compuestas. Por ejemplo, en la siguiente tabla queremos encontrar el número de palabras iguales a
gris:
Sub Búsqueda_En_Tabla()
Dim Mi_Tabla(3) As String
Dim Tab_Resultado() As String
Dim i As Long
Dim Palabra_Buscada As String
El resultado muestra un solo cuadro de diálogo con la palabra ”gris”. Los demás términos que contienen ”gris” no se tienen en
cuenta gracias al test.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 9-
Antes hemos visto cómo transferir el contenido de un rango de datos a una tabla en la memoria. El procedimiento
inverso también funciona.
El único problema aquí es indicar correctamente el tamaño del rango de celdas que hay que seleccionar para copiar
en él el contenido de la tabla en la memoria. Utilizando las instrucciones del tamaño de la tabla con la
instrucción ReSize, podemos definir fácilmente el rango de celdas. Debemos considerar, sin embargo, los casos
de tablas de una y dos dimensiones.
Hemos visto que transfiriendo el contenido de un rango de celdas de una columna o varias a una tabla (sección Carga
desde una hoja de cálculo de este capítulo), la tabla en la memoria debía tener necesariamente dos dimensiones:
una para las filas y otra para las columnas.
Por tanto, para volver a copiar el contenido de una tabla de dos dimensiones sin conocer exactamente su tamaño,
podemos escribir la siguiente instrucción, que se adaptará exactamente al tamaño de la tabla:
’Option Base 1
Range("A1").Resize(UBound(MiTabla), UBound(MiTabla, 2)) = MiTabla
’Option Base 0
Range("A1").Resize(UBound(MiTabla)+1, UBound(MiTabla, 2)+1) = MiTabla
Curiosamente, hacer que el contenido de una tabla sea de una dimensión no es tan sencillo. ¿Hay que devolver la tabla
horizontal o verticalmente? Si queremos devolverla horizontalmente, que es el caso más simple, podemos usar una de
estas sintaxis.
Sub Test_Tabla()
Dim MiTabla As
Variant
’ Carga de la tabla en memoria
MiTabla= Array(1, 2, 3, 4)
’ Descarga en la hoja de cálculo
Range("A1:D1") = MiTabla
’ O también
Range("A1").Resize(1, UBound(MiTabla)+1) = MiTabla
End Sub
Para copiar de nuevo el contenido de una tabla de una dimensión verticalmente, no basta con invertir los parámetros
de la instrucción Resize. De hacerlo, solo el primer elemento de la tabla se repetirá tantas veces
como elementos contenga la tabla.
Sub Test_Tabla()
Dim MiTabla As
Variant
’ Carga de la tabla en memoria
- 10 - © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
MiTabla= Array(1, 2, 3, 4)
’ Descarga en la hoja de cálculo
Range("A1:A4") =Application.Transpose(MiTabla)
’ O también
Range("A1").Resize(1, UBound(MiTabla)+1) = _
Application.Transpose(MiTabla)
End Sub
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 11 -
Las celdas con nombre y las tablas
1. Presentación
En Excel es posible atribuir un nombre específico a una celda o un rango de celdas. Resulta muy práctico para
personalizar las fórmulas, pero también proteje las referencias de las celdas y este es el tipo de seguridad que
buscamos en nuestros programas.
Partimos de un caso muy simple de tabla (Ejemplo 15D1) en la que tenemos una celda con la tasa de IVA. Pero la
referencia de la celda no es solo C1, también le hemos atribuido el nombre de Mi_IVA.
Método 1
Sitúese en C1.
Método 2
Sitúese en C1.
En lo que respecta a los programas, ¿cómo podemos integrar celdas con nombre? Pues bien, basta simplemente con indicar
el nombre en un método Range o escribirlo entre corchetes para recuperar el contenido de la celda.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Dim Tasa_IVA As Double
Tasa _ IVA = Range("Mi_IVA") ’Primera
escritura
Tasa _ IVA = [Mi_IVA] ’Segunda escritura
En ocasiones ocurre que alguna de estas dos sintaxis hace que el programa se detenga ya que el VBA tiene dudas sobre
qué información debe recuperar. En esos casos, basta con añadir la propiedad Value después de la instrucción y
ya no se produce el bloqueo.
La gran ventaja de utilizar celdas con nombre en programación es que siempre se podrá recuperar el contenido de la celda, incluso
cuando la posición de las celdas cambia a raíz de los cambios en el libro.
Con frecuencia, en efecto, se añaden o eliminan columnas en los libros y, por tanto, las coordenadas de las celdas se
modifican. Si construye los programas con referencias de tipo Cells(4,2), se verá obligado a corregirlos, pero
con celdas con nombre no será preciso tocarlos.
Otra de las grandes ventajas de usar celdas con nombre es la posibilidad de detectar inmediatamente la posición de la celda
con nombre o del rango con nombre mediante las propiedades Row y Column.
Por ejemplo, si trabaja en un libro que contiene una celda llamada Fecha_de_Factura, y sabe que debe indicar
exactamente cuatro filas por debajo del importe de la factura, podrá poner el valor de la fila de la celda en una
variable y usarla de nuevo de la forma siguiente:
Pero también podemos reducir la escritura a una sola línea de código de la siguiente manera:
Por tanto, si trabaja en libros bien estructurados, le resultará fácil navegar cómodamente en su interior basándose en las celdas
con nombre sin tener que borrar el contenido de toda una hoja hasta encontrar la celda buscada.
La lista de propiedades y métodos vinculados a una celda con nombre es muy importante. Bastará con recurrir a la depuradora
para que esa lista aparezca en la ventana Inspecciones.
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Del mismo modo, es posible recuperar el nombre de la hoja de cálculo donde está posicionada la celda activa
escribiendo la siguiente línea de código:
Hoja_Celda = [Mi_Celda].Worksheet.Name
Las tablas, que no se deben confundir con las tablas en la memoria, son herramientas muy potentes de Excel, pero
todavía son bastante poco usadas por los usuarios. Es todavía raro encontrar libros con tablas incorporadas.
A modo de recordatorio diremos que las tablas son los objetos que se obtienen activando el menú Insertar Tabla.
Al igual que las celdas con nombre, las tablas se identifican con nombres únicos y columnas con nombre. No solo es
posible trabajar en rangos de datos con un nombre único el nombre de la tabla sino también navegar dentro de
la tabla entre las columnas de ese objeto Tabla.
a. El objeto ListObject
Para encontrar todas las tablas dentro de un libro, basta con hacer un bucle con la instrucción For Each. A
continuación, solo deberá añadir la propiedad Name para obtener los nombres de las tablas.
La instrucción ListObject debe asociarse a una hoja de cálculo. ListObject sola no funciona. Esto acarrea líneas de
código muy largas para mostrar la fila de totales de una tabla, como podemos ver a continuación.
ActiveSheet.ListObjects("Tabla_Ejemplo").ShowTotals = True
Para simplificar la escritura, aconsejamos que ponga el objeto Tabla dentro una variable personal y trabaje con esa variable
de la siguiente manera:
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 3-
Dim Mi_Tabla As Object
Set Mi_Tabla = ActiveSheet.ListObjects("Tabla_Ejemplo")
Mi_Tabla.ShowTotals = True
Cuando se trabaja con tablas existe un gran número de propiedades específicas que es importante detallar.
Los encabezados de las tablas son muy importantes ya que su nombre se corresponde también con el de las
columnas como objeto VBA.
Sin tabla deberíamos encontrar en la programación la posición del encabezado de las columnas y también efectuar un test
para determinar la última columna para detener el bucle. En este ejemplo, todos esos controles no son necesarios ya
que nos basamos en los nombres de los objetos (Tablas y Columnas) cuyos tamaños y posiciones conocemos.
Para insertar una columna entre otras dos dentro una tabla (después de la columna Nombre, por ejemplo),
deberemos primero encontrar la posición de la columna en la tabla de la siguiente manera:
A continuación, bastará con usar ese dato para indicar que vamos a añadir una columna después de esa.
Mi_Tabla.ListColumns.Add Position:=(Col_Nombre + 1)
En este ejemplo no se han usado bucles para encontrar la posición o insertar la columna, hecho que hace ganar mucho
tiempo cuando se trabaja con tablas de gran tamaño.
En este capítulo hemos visto cómo cargar fácilmente el contenido de un rango de celdas dentro de una tabla en la memoria de la
siguiente forma Mi_Tabla = Range("A1:A10").
Para ello será preciso que conozcamos previamente el rango que vamos a insertar en nuestra tabla en la memoria,
mientras que, trabajando con una tabla, podemos cargar toda una columna sin necesidad de conocer las referencias de las celdas.
- 4- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Dim Mi_Columna As Variant
Set Mi_Tabla = ActiveSheet.ListObjects("Tabla_Ejemplo")
Set Mi_Columna = Mi_Tabla.ListColumns("Nom").DataBodyRange
Recálculos sistemáticos
Debe saber que todas las fórmulas presentes en las tablas se vuelven a calcular sistemáticamente cada vez que se
produce una modificación. Si añade una columna, toda la tabla vuelve a calcularse; si elimina un valor, toda la tabla
vuelve a calcularse; si añade una nueva fila, toda la tabla vuelve a calcularse, etc. Resulta muy frustrante.
Para evitar que el programa se ralentice inútilmente debido a esta especificidad, es posible indicar que desea
bloquear los cálculos automáticos al inicio del programa usando la siguiente instrucción:
Application.Calculation = xlManual
Por supuesto, si durante el programa fuera preciso añadir una fórmula será imperativo que ponga en marcha de nuevo
el cálculo automático justo antes de la instrucción de cálculo.
Application.Calculation = xlAutomatic
A lo largo del manual, hemos detectado la última fila de un documento de las siguientes formas:
Ahora bien, en una tabla estas instrucciones no funcionarán, ya que ambas instrucciones devolverán siempre la última fila
declarada de la tabla, sin tener en cuenta si está o no vacía.
Al programar, las tablas deben verse como globos en medio de la hoja de cálculo. Las tablas tienen sus propias reglas y usan
sus propios términos.
Por ejemplo, el siguiente código redimensiona la tabla exactamente a los datos contenidos en el documento. Podrá
encontrar el código en el archivo Ejemplo 15D4 desde la página Información.
Sub Cambio_tamaño_Tabla()
Dim Mi_Tabla As Object, ObjColumna As Object
Dim NumFilas As Long, ColNombre As Long
Dim UltimFila As Long, PrincFilaAs Long
Dim RangoActual As Variant
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 5-
Set Mi_Tabla = ActiveSheet.ListObjects("Tabla_Ejemplo")
’Encontrar el rango de la tabla (con encabezado)
RangoActual= Range("Tabla_Ejemplo[#All]").Address
’Supresión de las filas de fin (cadena de caracteres) RangoActual=
Left(RangoActual, InStrRev(RangoActual, "$"))
’Primera fila de la tabla (encabezado)
PrincFila= Range("Tabla_Ejemplo[#All]").Row
’Posición de la primera columna
ColNombre = Range("Tabla_Ejemplo").Column
’Número de filas en las tablas
NumFilas= Mi_Tabla.ListRows.Count
’Carga de la primera columna en la memoria
Set ObjColumna = Mi_Tabla.ListColumns(1).DataBodyRange
’Detección de la última fila con info
UltimaFila= Application.CountA(ObjColumna) + PrincFila
’ Cambio tamaño de la tabla
Mi_Tabla.Resize Range(RangoActual&
ÚltimaFila) End Sub
- 6- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Una API para los milisegundos
Para poder medir la velocidad de ejecución de un programa, las funciones internas de fechas y horas de VBA no son
suficientes, ya que es necesario realizar cálculos del orden de la centésima o milésima. Por lo tanto, vamos a utilizar una
API que será capaz de realizar este cálculo.
Tras haber declarado tres funciones que llaman a las otras tres a la misma dll, vamos a colocar en el programa las cuatro
líneas siguientes para iniciar su contador de tiempo y después, al final del programa, para detener el contador y escribir el
resultado en una celda.
Sub Pgm_Principal()
’ Colocar al principio del programa
timeBeginPeriod 1
t_start = timeGetTime()
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
El entorno de 64 bits
Los nuevos ordenadores están diseñados con procesadores de 64 bits para gestionar mejor los datos y asumir más de 6 Gb
de memoria. Microsoft ha secundado esta innovación proponiendo versiones desde Office 2010 de 64 bits que vienen con
la versión 7 de VBA. Esta evolución no es desdeñable en los programas que llaman a las API.
La gran mayoría de API llamadas en VBA son Kernel32.dll, shell32.dll, user32.dll. Como sus propios nombres indican,
estos archivos están diseñados para funcionar en un entorno de 32 bits, de ahí los problemas en la migración de macros
desde una versión de 32 bits hacia una plataforma de 64 bits.
1. La instrucción PtrSafe
Para permitir la ejecución de las API en un entorno de 64 bits, basta con indicar tras su Declare la instrucción
PtrSafe para que la llamada de la API sea segura. Por ejemplo, puede tener:
Pero la instrucción PtrSafe no es suficiente para hacer segura la llamada. En efecto, y como ya hemos visto en el
capítulo Las variables con presentación de los tipos de variables, la arquitectura de 64 bits impone dos nuevos tipos
de variables: LongLong y LongPtr.
El tipo LongPtr es capaz de gestionar por igual las variables de 32 o 64 bits en función de las necesidades. Pero solo se
debe utilizar para punteros u objetos.
Private Declare PtrSafe Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" (ByVal
Hwnd As LongPtr, ByVal lpOperation As String,_ByVal lpFile As String, ByVal
lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As
LongPtr
Como acabamos de ver, la llamada a las API no es la misma en los dos sistemas. Sin embargo, podemos escribir un programa que
será comprensible tanto por una arquitectura de 32 bits y como de 64, e incluso, por un Office de 32 bits que funciona en una
plataforma de 64 bits.
Para realizar esto, basta con crear una condición If al nivel de su módulo, fuera de cualquier procedimiento. Ahora bien, siempre
hemos dicho que no era posible escribir ni una sola línea de código fuera de un procedimiento, por eso debemos hacer preceder a
nuestras instrucciones por el símbolo #. El siguiente código, en función de la versión de
su Office (VBA7) y de su arquitectura (Win64) atribuirá el tipo LongPtr a nuestras variables que empiecen por la
letra Z. VBA7 tiene como valor True en Office 2010 y 2013.
’Definición del tipo de datos por defecto para las variables que empiezan por Z
#If Win64 And VBA7 Then
DefLngPtr Z
#Else
DelLng Z
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
#End If
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Introducción
Es muy habitual, en el ámbito profesional, querer optimizar la exportación de sus hojas o sus libros, ya sea
generando archivos pdf, o también generando automáticamente correos electrónicos.
Hasta la versión de Excel 2003, para realizar estas tareas, había que utilizar dll complementarias, pero desde la
llegada de la versión de Office 2007 y con los complementos de las aplicaciones Acrobat, es mucho más simple crear
programas de exportación sin llamar a las dll externas.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Eliminar las dll que faltan
Uno de los mayores problemas con el que nos encontramos actualmente en la migración de programas escritos en Excel
2003 hacia una versión más reciente, es la llamada a librerías (dll) que ya no existen. Y el impacto en su programa a
menudo supera incluso el ámbito del uso de esta antigua librería.
Efectivamente, es corriente que un programa que llama a una antigua librería se detenga en las funciones básicas como
Range, Ucase, etc. Si se encuentra ante un caso similar, debe tener los reflejos para comprobar las librerías llamadas por
su programa.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Llamada a una biblioteca inexistente en su proyecto.
Sin entrar en detalles de las distintas bibliotecas llamadas, puede ver en el ejemplo siguiente que una dll está
marcada como FALTA. Esto sucede frecuentemente cuando el programa llama a antiguas dll de Office (calendar o
spreadsheet) o a dll complementarias por ejemplo para exportan a PDF.
En este caso:
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
La instrucción CreateObject
Para llamar a programas ya instalados en su ordenador, debe utilizar la función CreateObject. Esta función
permite llamar desde un programa VBA a las funciones de otros programas como, por ejemplo, el envío de emails, la
generación de documentos PDF, etc.
En resumen, basta con que indique el nombre del programa al que quiere llamar y Visual Basic se encargará de
encontrarlo en la base de registro de su ordenador en la que está guardado.
Pero crear un objeto que corresponda a una aplicación no es suficiente, a continuación hay que crear un nuevo objeto para
abrir una nueva instancia en esta aplicación. En los dos párrafos siguientes, veremos dos ejemplos de uso de la
función CreateObject.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Envío de emails Outlook
En muchas empresas que necesitan hacer envíos masivos de correos (mailing), el uso de macros es ineludible. El código
siguiente lo ha creado otro Microsoft MVP Excel, Ron de Bruin. Encontrará otros tutoriales (en inglés) en su
página: http://www.rondebruin.nl/win/section1.htm
El código funciona con la mayoría de programas de correo electrónico, excepto para los de Lotus Notes.
Sub Mail_small_Text_Outlook()
’Working in Office 2000-2013
Dim OutApp As Object
Dim OutMail As Object
Dim Cuerpo_Mail As String
Dim Mail_Destinatario As String
Como podrá comprobar, el código no es muy largo. Ahora vamos a estudiarlo punto por punto y verá que el código es muy
simple y que nada es superfluo.
Tras la declaración de las variables, creamos dos objetos. El primero OutApp, permite llamar al programa Outlook y el segundo
crea un nuevo mensaje: creación de un mensaje ( CreateItem) en el objeto OutApp que corresponde
a la aplicación Outlook.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
A continuación escriba el mensaje que va a enviar a sus destinatarios. Para insertar saltos de línea, puede utilizar la
constante vbNewLine, pero también el carácter salto de línea con la instrucción Chr(10) o Chr(13) como vimos
en el capítulo Administrar las listas de caracteres así como en el anexo.
Además, puede personalizar el mensaje usando balizas HTML. Por ejemplo, si desea poner en negrita el nombre de su
interlocutor, escribirá el mensaje de la siguiente manera:
l el destinatario (To)
l el envío (Send) o la vista previa (Display). Puede escoger una u otra, pero no las dos opciones.
Por último, cierre los dos objetos para liberar la aplicación llamada.
Si sus contactos están todos recogidos en la columna A de su libro de Excel, puede englobar todo el código anterior en un
bucle similar a este código:
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Creación de un archivo PDF
Desde que la empresa Adobe (Acrobat Reader) integra una dll de creación de pdf en el directorio Office en la
instalación de sus productos, es fácil llamar a esta librería para generar un archivo pdf de su libro.
De nuevo, vamos a reutilizar el código de Ron de Bruin que Microsoft emplea en sus tutoriales.
A diferencia de la creación de un mail, en primer lugar vamos a crear una función que administrará la creación del
archivo PDF.
l La ruta de acceso de su archivo. Si la ruta está vacía "", entonces la ventana Guardar como aparecerá durante el proceso de
publicación.
l Parámetro para indicar si quiere eliminar (True) o conservar (False) la versión anterior del PDF, si existe.
l Parámetro para indicar si quiere abrir el archivo en Acrobat Reader al final del tratamiento.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
On Error Resume Next
Myvar.ExportAsFixedFormat _
Type:=xlTypePDF, _
FileName:=Fname, _
Quality:=xlQualityStandard, _
IncludeDocProperties:=True, _
IgnorePrintAreas:=False, _
OpenAfterPublish:=OpenPDFAfterPublish
On Error GoTo 0
Se puede llamar a esta función para exportar todo un libro o una simple hoja del libro en formato PDF.
Para exportar todo un libro a PDF, debe llamar a la función creada anteriormente con el siguiente procedimiento:
Sub RDB_Workbook_To_PDF()
Dim FileName As String
MsgBox "No es posible crear PDF por una de las razones siguientes:
" & vbNewLine & _
Este programa le permitirá enviar una o varias hojas de cálculo en la función de creación de un archivo PDF.
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
En este caso, solo hay una diferencia con respecto al código anterior, es el paso como parámetro de la instrucción
ActiveSheet que corresponde a una o varias hojas seleccionadas.
Sub
RDB_Worksheet_Or_Worksheets_To_
PDF() Dim FileName As String
End If
End Sub
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 3-
Conectar con una base de datos Access
1. Presentación
Desde un programa desarrollado con VBA en Excel, es posible conectar con una base Access y trabajar con los dos
programas en paralelo para explotar los datos de un programa en el otro. Trabajando con Access desde Excel, es posible
es posible recuperar solo los datos que quiere explotar. De esta forma, no recargará el libro de Excel con datos inútiles.
Para relacionar las aplicaciones de Office, deberá pasar por ActiveX Data Objects (ADO).
Para activar el ADO, con VBA, abra el menú Herramientas Referencias... y active la opción Microsoft
ActiveX Data Objects 6.0 Library (u otra versión disponible en su ordenador).
Sin esta funcionalidad, no será posible interpretar las líneas de código que presentamos a continuación.
2. Puesta en marcha
Para trabajar en bases de datos Access desde Excel, utilizaremos dos objetos: ADOBD.Connection y
ADODB.RecordSet.
El objeto ADOBD.Connection permite conectarse a una base de datos. El objeto ADOBD.RecorSet contendrá el resultado
de la consulta.
El principio consiste en declarar las bases de datos a través de una conexión. Si la conexión funciona, podremos ejecutar las
consultas mediante la instrucción RecordSet.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Dim Mi_Consulta As New ADODB.Recordset
Será necesario acceder al componente Microsoft Jet, pero es inútil que nos entretengamos en explicaciones sobre su
funcionamiento; deberá precisar el nombre y la ruta de la base de datos en el parámetro Data Source.
Para asegurarse de que la base se ha abierto correctamente puede comprobar que no haya ningún error con el
siguiente texto:
If Mi_Base.Errors.Count = 0 Then
Instructions
End If
En la parte Instrucciones recurrirá al objeto RecordSet para transmitir la consulta. Los parámetros que debe
transmitir son:
l El objeto Connection.
l Un parámetro de acceso que hay que dejar por defecto en adOpenForwardOnly.
Para comunicarse entre Excel y bases de datos como Access, puede transmitir las instrucciones en lenguaje SQL o por línea de
comandos, como veremos en los siguientes ejemplos.
If Mi_Consulta.Status = 0 Then
En el caso de que su consulta SELECT devuelva varias líneas, es posible copiar todo el RecordSet, sin bucles, dentro
de un rango de celdas en una sola línea de código usando la instrucción CopyFromRecordset.
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Range("A1").CopyFromRecordset Mi_Consulta
A continuación encontrará un ejemplo completo de acceso a una tabla Access que también podrá consultar en el
archivo Ejemplo 16Access1.xlsm desde la página Información.
Sub Consulta_Access_SELECT()
Dim Mi_Base As New ADODB.Connection
Dim Mi_Consulta As New ADODB.Recordset
Dim Base_Data As String
Dim SQL_Req As String
’Ubicación y Nombre de la base de datos
Base_Data = "C:\Users\Base_Access_Ejemplo.accdb"
’ Abrir la conexión con la base de datos
Set Mi_Base = New ADODB.Connection
Mi_Base.Open "Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source="Ba&se_Data & ";"
’ Creación de la consulta
SQL_Req = "SELECT * From Table1"
’Ejecución de la consulta
Mi_Consulta.Open SQL_Req, Mi_Base, adOpenForwardOnly
’Test para cerciorarse de que no hay errores en el acceso a la tabla
If Mi_Consulta.Status = 0 Then
’copia de la consulta en celda A1
Range("A1").CopyFromRecordset Mi_Consulta
End If
’Cierre del RecordSet y de la conexión
Mi_Consulta.Close
’Cierre de la conexión a la base para liberar memoria
Mi_Base.Close
End Sub
Desde Excel pueden añadirse nuevos registros a una base de datos. Esto puede hacerse a través de una consulta
SQL o bien añadiendo métodos al objeto RecordSet. A continuación presentamos este último método, pero en el archivo
Ejemplo 16Access2.xlsm, encontrará las dos soluciones.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 3-
Set Mi_Base = New ADODB.Connection
Mi_Base.Open "Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source=" & Base_Data & ";"
La primera parte, que concierne a la conexión a la base, es exactamente igual que con la instrucción SELECT.
l Fields: cumplimentado de los diferentes campos de la tabla, ya sea dando el nombre de la columna, ya sea dando el valor del
índice de la columna partiendo de 0.
También es posible actualizar registros en las tablas a partir de los datos contenidos en hojas de cálculo. En esos casos,
resulta más sencillo realizar la tarea mediante una consulta SQL que hacerlo con los métodos del objeto
RecordSet.
El código, que es posible consultar desde la página Información, Ejemplo 16Access3.xlsm, es el siguiente:
Sub Consulta_Access_UPDATE()
Dim Mi_Base As New ADODB.Connection
Dim Mi_Consulta As New ADODB.Recordset
Dim Base_Data As String
Dim SQL_Req As String
Dim i_Fila as Long
- 4- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
’Ubicación y Nombre de la base de datos
Base_Data = "C:\Users\Base_Access.mdb"
’ Abre la conexión a la base
Set Mi_Base = New ADODB.Connection
Mi_Base.Open "Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source=" & Base_Data & ";"
’Ejecución de la consulta
Mi_Base.Execute SQL_Req
i_Fila = i_ Fila + 1
Wend
’Cierre de la conexión
Mi_Base.Close
End Sub
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 5-
Repaso del inicio por Visual Basic Editor
Hasta ahora, hemos iniciado los programas a través de Visual Basic Editor haciendo clic en el icono o pulsando la
tecla [F5] .
Pero también puede iniciar un programa desde una hoja de cálculo de varias formas distintas.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Combinación de teclas [Alt][F8]
Desde una hoja de cálculo, pulsando las teclas [Alt][F8] , aparecerá el siguiente cuadro de diálogo:
En este cuadro de diálogo no aparecen todos los procedimientos o funciones de su aplicación: solo se muestran los procedimientos
sin parámetros.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Inicio mediante un botón u otro objeto
También puede provocar el inicio de un programa insertando controles en una hoja de cálculo. En la
l controles de formulario,
l controles ActiveX.
Los controles de formulario proceden de las antiguas versiones de Excel; se siguen conservando para asegurar la
compatibilidad con versiones anteriores de los libros. Se pueden seguir usando en Excel 2007, 2010 y 2013.
Los controles ActiveX son similares a los controles de un cuadro de diálogo personalizado (UserForm) (ver el capítulo
siguiente), estos poseen más propiedades que los controles de formulario. En los ejemplos de este capítulo, solo
utilizaremos los controles de formulario ya que son más sencillos de utilizar a nivel de hojas de cálculo.
1. Los botones
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
El puntero del ratón se transforma en una cruz con líneas finas, esto significa que puede dibujar un objeto en la hoja
de cálculo.
Cuando haya dibujado el botón, aparecerá un cuadro de diálogo con la lista de procedimientos que es posible
seleccionar.
Este cuadro de diálogo le pide que asigne al botón uno de los procedimientos sin parámetros. Como ocurre con la combinación
de teclas [Alt][F8] , solo puede seleccionar los procedimientos sin argumento.
Acaba de crear un botón en su hoja de cálculo: cada vez que haga clic en él, ejecutará la macro asociada al botón.
Cada botón de opción presenta una elección posible pero solo se puede activar una de estas opciones a la vez.
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Basta con hacer un test a cada botón de opción para saber cuál está seleccionado.
Tomemos el ejemplo de la visualización de la hora en una hoja de cálculo. Hay dos casos posibles: la detención de la
actualización (que fija la hora mostrada) o la activación de la actualización automática para visualizar los segundos que
transcurren.
Haga clic con el botón derecho del ratón en la celda A2 y escoja Formato de celdas.
En la pestaña Programador, haga clic en el botón Insertar y después en la herramienta Botón de opción
en los controles de formulario.
Para modificar su nombre, haga clic en el objeto para seleccionar el nombre actual o haga clic con el botón derecho del
ratón sobre el objeto para hacer aparecer el menú contextual:
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 3-
Después haga clic en Modificar texto.
A continuación, seleccione el botón ON y haga clic en la opción Formato de control del menú contextual.
En el cuadro de diálogo que aparece, seleccione en la pestaña Control una celda en su hoja de cálculo;
por ejemplo, la celda A1:
Tras aceptar, cuando seleccione uno de los dos botones de opción, el valor de A1 cambiará. Vamos a construir el código en
función de este valor.
- 4- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Sub Test_Activo()
While Cells(1, 1) = 1
Calculate
DoEvents
Wend
End Sub
Por último, debe asociar todos los botones de opción a este mismo procedimiento : haga clic con el botón derecho
y seleccione la opción Asignar macro.
Aparecerá un cuadro de diálogo: seleccione el procedimiento que desea iniciar cada vez que se seleccione un
botón de opción.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 5-
Por consiguiente, cada vez que escoja una de las dos opciones, verá cómo la hora cambia o bien se mantiene fija.
También puede agregar menús desplegables en su hoja de cálculo y asociarle una macro: según la opción escogida, su
macro se comportará de un modo distinto.
- 6- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
En la zona Rango de entrada, seleccione el rango de celdas que se visualizará en el menú desplegable. En la
zona Vincular con la celda, escoja una celda: cada vez que seleccione un elemento de la lista
desplegable, la celda vinculada mostrará el rango del elemento en esta lista.
Por ejemplo, si en la columna A tiene los doce meses del año, pondrá en el rango de entrada las celdas A1:A12 y en la
celda vinculada la celda B1.
El archivo Ejemplo 17C3 corresponde a un calendario dinámico en función de los valores contenidos en el menú desplegable
de los meses y los años:
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 7-
Sin embargo, el archivo no es perfecto ya que el calendario muestra siempre 31 días, sea cual sea el mes escogido. Vamos
a crear una macro que ocultará los días cuando el mes seleccionado no tenga 31 días.
En primer lugar, utilizaremos la Grabadora de macros para recuperar el código que permite ocultar y mostrar
una columna:
Columns("AF:AF").Select
Selection.EntireColumn.Hidden = True
Columns("AE:AG").Select
Selection.EntireColumn.Hidden = False
Una posible solución (pero no la única) consiste en hacer un test en las distintas celdas que contienen una fecha y después
comprobar si el valor Mes de las celdas sigue siendo igual al mes seleccionado en el menú desplegable; esto equivale a
hacer un test al valor de la celda vinculada .
En torno a este test, vamos a construir un bucle con las tres últimas columnas. Todos los meses tienen al menos 28 días,
por lo tanto no es útil hacer un test en los días 1 a 28.
Sub Ocultar_los_Días()
Dim Núm_Col As Integer
For Núm_Col = 30 To 32
If Month(Cells(5, Núm_Col)) <> Cells(3, 4) Then
Columns(Núm_Col).Hidden = True
Else
Columns(Núm_Col).Hidden = False
End If
Next
End Sub
El error en este programa sería no volver a mostrar las columnas en caso de que se pase de un mes de 30 días a un mes de 31
días: si no prevé mostrar las columnas para los días 29, 30 y 31, estas columnas siempre estarán ocultas.
- 8- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Cuando introduce objetos en una hoja de cálculo, no siempre es fácil alinearlos. En efecto, no es posible activar una
casilla que permita asegurar una alineación y una distancia entre los objetos. Por lo tanto, puede tener objetos
colocados un poco al azar como estos:
Aunque esta alineación se podría hacer mediante las opciones de la pestaña Diseño de página, vamos a escribir una
macro que colocará las casillas en las celdas respetando las propiedades de tamaño de las celdas. Vamos a crear un
bucle en cada objeto de la hoja empezando por la colección de objetos.
Sub BucleCheckBoxes_Formulario()
Dim Cb As CheckBox
For Each Cb In Hoja1.CheckBoxes
Instrucciones
Next Cb
End Sub
Para colocar un objeto en una celda, vamos a recuperar la celda en la que el objeto está colocado mediante la
propiedad Shape.TopLeftCell. La esquina superior izquierda del objeto es el punto de referencia.
Sub BucleCheckBoxes_Formulario()
Dim La_Celda as Range
Dim Cb As CheckBox
Dim La_Celda as Range
For Each Cb In Hoja1.CheckBoxes
Set La_Celda = Cb.TopLeftCell
Next Cb
End Sub
A continuación, utilizaremos las propiedades Left (izquierda) y Top (arriba) para definir la posición y las
propiedades Height (altura) y Width (anchura) para definir las dimensiones del objeto y recolocar cada casilla de
verificación.
Sub BucleCheckBoxes_Formulario()
Dim La_Celda As Range
Dim Cb As CheckBox
For Each Cb In Hoja1.CheckBoxes
Set La_Celda = Cb.TopLeftCell
With Cb
.Select
.Left = La_Celda.Left + 2
.Top = La_Celda.Top
.Height = 15
.Width = 75
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 9-
End With
Next Cb
End Sub
Tras la ejecución de este programa, todos los objetos se colocarán de la misma forma con respecto al alto de las filas de
la hoja de cálculo.
- 10 - © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Procedimiento Auto_Open/Auto_Close
Puede iniciar un programa al abrir un libro poniendo en este un módulo que contenga un procedimiento llamado
Auto_Open. Así, al abrir un libro, las líneas de código contenidas en este procedimiento se ejecutarán
automáticamente al inicio.
Sub Auto_Open()
Instrucción
End Sub
Del mismo modo, puede iniciar un programa al cerrar el libro añadiendo en un módulo, un procedimiento llamado
Auto_Close.
Sub Auto_Close()
Instrucción
End Sub
Por ejemplo, puede forzar el guardado del libro al cerrarlo escribiendo este sencillo fragmento de código.
Sub Auto_Close()
ActiveWorkbook.Sav
e
End Sub
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Evento en una hoja de cálculo
Tiene la posibilidad de iniciar procedimientos desde una hoja de cálculo mediante un doble clic o seleccionando una celda.
Para ello, es necesario que cree un código en una hoja de cálculo y no en un módulo.
Como muestra la imagen precedente, a la derecha del VBE tenemos el editor de código, pero en el explorador de
proyectos, a la izquierda, no tenemos ningún módulo.
También habríamos podido seleccionar la opción ThisWorkbook para que el código se aplicara a todas las hojas de
cálculo del libro y no solo a una de ellas.
Sin embargo, cuando escribimos un código desde una hoja de cálculo o para todo el libro no trabajamos con
procedimientos estándar sino con procedimientos ocasionales. Es decir, procedimientos que se activarán cuando se
produzca un evento en la hoja de cálculo, como por ejemplo un doble clic.
2. Lista de eventos
La lista de eventos puede variar dependiendo de la versión de Excel. Pero no se preocupe, los ejemplos que
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
aparecen a continuación se aplican a todas las versiones de Excel.
Si se encuentra en el objeto ThisWorkbook, la lista de eventos será diferente y se aplicará a los eventos del libro
(abrir, activar, etc.).
3. El evento Change
El evento se comportará de la manera siguiente: los cambios en las celdas conducirán a la ejecución del
procedimiento. Por ejemplo, vamos a hacer un programa que ocultará la columna B cuando el valor de la celda A1 sea
igual a "Sí" y que mostrará la columna B cuando el valor de la celda A1 sea distinto de "Sí".
Vamos a crear el código siguiente en un procedimiento Worksheet_Change (este procedimiento deber estar en una hoja y
no en un módulo).
Para simplificar la escritura de la palabra "Sí" haremos que el contenido de la celda sea en minúsculas usando la instrucción
LCase. De esta forma, el evento podrá interpretarse siempre, independientemente de cómo el usuario
lo escriba.
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
4. El parámetro Target
El parámetro Target corresponde a la celda que activa el evento. La variable es un objeto en el sentido de que varios
métodos y propiedades están vinculados al parámetro Target.
En los ejemplos que presentamos a continuación veremos cómo usar esas propiedades en los tests.
5. Controlar la selección
Para evitar un error de selección, puede agregar un control al número de celdas seleccionadas. En el siguiente
ejemplo, si selecciona más de una celda, la parte del código que oculta la columna B no se leerá:
Columns("B").Hidden = False
End If
End If
End Sub
6. El evento SelectionChange
Con el evento Change hemos visto que podíamos iniciar el programa cuando se había modificado el contenido de una
celda,pero también podemos iniciarlo cuando cambiamos de celdas. Para ello usaremos el evento
SelectionChange.
Por ejemplo, para colorear a la vez la línea y la columna de la celda activa, el código será:
Cells.Interior.ColorIndex = xlNone
Fila = Target.Row
Columna = Target.Column
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 3-
Set RngRow = Rows(Fila)
Set RngCol =Columns(Columna)
Set RngFinal = Union(RngRow, RngCol)
Este evento podría resultar peligroso ya que anula el comportamiento estándar del doble clic en las hojas de
cálculo, es decir, el paso a modo edición.
Por tanto, para permitir que se eluda el comportamiento estándar del doble clic, se recomienda definir siempre el rango
de aplicación del evento.
Por ejemplo, con el siguiente código permitimos omitir el doble clic personalizado en el rango de celdas B5:B10.
- 4- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Introducción
En el capítulo sobre las variables vimos cómo ofrecer a los usuarios la posibilidad de transmitir valores al programa
usando la instrucción InputBox. Ocurre que esta instrucción es muy limitada, ya que no dispone de opciones para
poder personalizarla.
Para mejorar esto, Visual Basic ofrece la posibilidad de crear sus propios cuadros de diálogo para proponer a los
usuarios que seleccionen datos que le servirán en su programa mediante botones de opción, casillas de verificación o menús
desplegables. Así, podrá comprobar los datos que se transmitan a su programa y evitará los errores de entrada.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Crear un cuadro de diálogo
En Visual Basic Editor, seleccione el menú Insertar UserForm o haga clic en el siguiente icono en la
barra de menús:
Aparecerá una nueva carpeta en el Explorador de proyectos, así como un rectángulo gris en la zona de trabajo.
Este rectángulo gris corresponde a un cuadro de diálogo en blanco. A continuación debe añadir los Controles
mediante el Cuadro de herramientas que aparece cuando ha seleccionado el UserForm.
Si el Cuadro de herramientas no se muestra o si, por descuido, lo ha suprimido, puede recuperarlo mediante
el menú Ver Cuadro de herramientas.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Puede cambiar el tamaño del cuadro de diálogo deslizando uno de los bordes del UserForm.
En la ventana de propiedades, verá todas las propiedades relacionadas con el objeto seleccionado:
Como podrá comprobar, existe una gran cantidad de propiedades relacionadas a un UserForm esto también
ocurrirá para los Controles que añadiremos más adelante. El objeto UserForm posee, entre otras, las siguientes
propiedades:
Además del aspecto gráfico de un cuadro de diálogo, un UserForm se compone también de líneas de código que se
encuentran fuera de los módulos. Estas líneas de código se conocen como Private y solo pueden ejecutarse
cuando se llama al cuadro de diálogo. Para mostrar estas líneas de código:
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Le recomendamos encarecidamente que cambie el nombre genérico (UserForm1) por un nombre que defina
mejor la función del cuadro de diálogo que va a crear: en la ventana de propiedades, cambie el
valor de la propiedad Name. Este nombre también se utilizará en su programa.
Para activar la visualización de un cuadro de diálogo personalizado desde un procedimiento, debe escribir su
nombre seguido del método Show.
Sub Programa_Principal
UserForm1.Show
End Sub
También puede visualizar su cuadro de diálogo desde Visual Basic Editor sin la instrucción Show:
Para trabajar con los controles del cuadro de diálogo, en primer lugar debe recordar el nombre de su UserForm, el nombre del
control y la propiedad del control:
Mi_Cuadro.Mi_Control.Propiedad
Cuando trabaje en el código integrado en el UserForm, podrá sustituir el nombre que ha atribuido a su UserForm
por Me.
Desde un módulo, la instrucción Me es incomprensible por Visual Basic. En ese caso, debe escribir el nombre exacto
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 3-
del UserForm para que se pueda interpretar.
Por ejemplo, para insertar la fecha del día en un cuadro de diálogo personalizado se puede escribir el código
siguiente desde el evento Activate:
Me.Label1.Caption = Date
Pero si desea efectuar la misma operación desde un módulo, deberá remplazar Me por el nombre del cuadro de diálogo
personalizado.
Userform1.Label.Caption = Date
- 4- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Los eventos
Un evento atañe a todas las acciones que pueden realizarse en un control. Cada evento es un tratamiento específico en el
control que no interfiere a los otros eventos de los demás controles.
Por ejemplo, puede inicializar valores cuando su cuadro de diálogo personalizado se active (Evento).
Tendrá que usar los eventos para comprobar los datos introducidos y también para transmitir los elementos seleccionados
a los módulos de su programa.
Para conocer la lista de eventos que pueden estar relacionados con un control, hay que seleccionar el nombre del control
en el menú desplegable situado en la parte superior de la zona de trabajo; en el segundo menú desplegable, encontrará la
lista de los eventos que el control puede administrar.
Los eventos se declaran en Private, ya que solo son visibles y accesible s desde el cuadro de diálogo.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Los controles
Un control es un objeto elemental utilizado para transmitir valores al programa. Los controles evitan tener que
escribir datos "literalmente" en un programa (como una ruta de acceso). Un control se ubica obligatoriamente en un
UserForm. Cada control posee sus propias propiedades.
Visual Basic propone controles que pueden clasificarse en las siguientes familias:
l Los controles textuales como los Labels (o títulos) y los TextBox (o cuadro de texto).
l Las listas son listados de elementos en las que los usuarios pueden elegir un elemento; pueden ser listas simples como los ListBox
(o cuadro de lista) o listas editables como los ComboBox (las listas desplegables).
l Los marcos agrupan visualmente los controles que tratan los mismos datos.
Cada control posee propiedades y eventos propios. El capítulo Los controles está dedicado exclusivamente al estudio
de los diferentes controles, junto con ejemplos de utilización.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Ubicación de los controles
Puede colocar libremente sus controles en un UserForm; gracias a la herramienta Cuadrícula, también puede
imponer un espacio concreto (medido en puntos) entre cada control.
Para mostrar los parámetros de la cuadrícula, active el menú Herramientas Opciones y seleccione
General.
Puede precisar el espaciado modificando las Unidades de la cuadrícula en Ancho y/o Alto (en número de
puntos).
Active la opción Forzar controles a cuadrícula para facilitar el posicionamiento de los controles en la
cuadrícula cuando los desplace.
Si esta opción no está marcada, se arriesga a crear cuadros de diálogo que se parecerán a este:
En este ejemplo, no hay ninguna coherencia entre los controles: el tamaño, la alineación y el espaciado entre los controles son
diferentes.
Sin embargo, incluso cuando la opción Forzar controles a cuadrícula está activa, no es siempre fácil colocar
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
correctamente los controles los unos con respecto a los otros.
Para ayudarle a alinear los controles y armonizar el espacio entre ellos, utilice el menú Formato. Tomando
como ejemplo el cuadro de diálogo anterior, vamos a ver cómo alinear los botones de opción.
Debe seleccionar previamente los controles trazando un marco ficticio con el ratón para englobar los
controles en cuestión.
El primer control seleccionado será el control base: es el único que está delimitado con cuadrados blancos. Este control
será la referencia para los demás en términos de tamaño, altura, posición, etc.
Para cambiar el control base, pulse la tecla [Ctrl] y haga clic en el control deseado.
Para alinear a la izquierda los controles con respecto al control base, active el menú Formato Alinear
Izquierda.
Automáticamente, todos los controles se alinearán al punto más a la izquierda del control base.
Para armonizar la altura de los controles OptionButton, seleccione los tres controles y active el menú
Formato Igualar tamaño Alto.
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Ahora todos los controles tendrán la misma altura.
Del mismo modo, si selecciona el menú Formato Igualar tamaño Ancho, ajustará el ancho de los
controles en función del ancho del control base:
Para ajustar el espacio entre los controles, seleccione el menú Formato Espacio vertical Aumentar y
después el menú Formato Espacio vertical Igualar.
Así, todos los controles estarán separados exactamente como la altura del control base.
Para alinear el botón Aceptar con el botón OptionButton2, seleccione solo esos dos controles, escoja como
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 3-
control base el botón de opción y utilice los siguientes menús:
Para acabar, seleccione los dos CommandButtons (con el control Aceptar como control base) y active los
menús:
- 4- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Orden de tabulación
Una vez que todos los elementos están colocados en el cuadro de diálogo, podrá utilizar la propiedad TabIndex de
cada uno de los controles para definir el orden de selección con la tecla [Tab] .
El número de orden que va a atribuir será obligatoriamente único. Si, por un descuido, atribuye el mismo número a dos
controles distintos, Visual Basic atribuirá automáticamente al segundo control el primer número de orden que esté libre.
Al final, durante la ejecución del programa, cada vez que pulse la tecla [Tab] , pasará de un control a otro según el orden
de los números atribuidos a cada control.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Introducción
Este capítulo presenta una serie de ejemplos que le mostrarán como usar los controles en los cuadros de diálogo
personalizados.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Las etiquetas (Labels o títulos)
Los usuarios no pueden modificar esta información. Generalmente se trata de títulos, elementos o información que se le
impone al usuario, como una fecha, por ejemplo.
Para agregar un control Label en un UserForm, haga clic en el icono del cuadro de herramientas. El
puntero del ratón se transforma en una cruz fina acompañada de una A mayúscula.
Por defecto, el nombre del control es Label1, Label2, etc. Para modificar este nombre, modifique la
propiedad Caption del control.
Para cambiar el título que se visualizará en el cuadro de diálogo, escriba el nombre del UserForm, el nombre del
control tal cual lo define la propiedad Name seguido de la propiedad Caption.
Por ejemplo, podemos escribir la fecha del sistema en el control Label1 de la siguiente forma:
Me.Label1.Caption = Date
Atención: no confunda la propiedad Caption (que corresponde a la palabra que se muestra en el cuadro de diálogo), con la
propiedad Name del control (que define el control en sí). Esto se aplica a TODOS los controles .
Por el contrario, si cambia la propiedad Name de su control (como por ejemplo La_Fecha), tendrá que escribir en su
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
línea de comando:
Me.La_Fecha.Caption = Date
Las propiedades más comunes del control Label son las siguientes:
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Los cuadros de texto (o TextBox)
Los controles TextBox permiten al usuario realizar entradas de texto.
Para agregar un control TextBox en un UserForm, haga clic en el icono del cuadro de herramientas. El
puntero del ratón se transforma en una cruz fina acompañada de abl.
La entrada de texto es libre en un control TextBox. Pero en cambio, puede realizar tests en la
información introducida por los usuarios en un evento asociado a la salida del control.
Las propiedades más comunes del control TextBox son las siguientes:
Tomemos por ejemplo un programa de cálculo financiero que requiere la introducción de una tasa de interés:
En este ejemplo, el dato introducido debe ser un valor numérico. Va a crear un test cuando el usuario abandone la zona
de texto para comprobar que la información escrita es un valor numérico.
Vamos a crear un test que comprobará que la información escrita es un valor numérico. Vamos a escribir en el evento
Exit (es decir, cuando el usuario abandone el control) el código que comprobará el contenido del control.
En el evento Exit, vamos a hacer un test a la propiedad Text del control TextBox para comprobar que su contenido es un valor
numérico. Nuestro test se escribirá de la siguiente forma:
El código puede mejorarse si realizamos un test únicamente cuando el control TextBox está compuesto por al menos un
carácter. Además, puede verificar que el valor está comprendido entre 0 y 10:
1. Agregar un botón
En el cuadro de herramientas, haga clic en el icono y con ayuda del ratón, dibuje el botón en el
cuadro de diálogo. Aparecerá un nuevo CommandButton.
2. El botón Cancelar
Cuando hace clic en el botón Cancelar de cualquier cuadro de diálogo, cierra el cuadro de diálogo, pero también borra
todos los parámetros en la memoria que se cargaron cuando estaba abierto ese cuadro de diálogo.
Haga doble clic en el control, para abrir directamente el código del control.
Para cerrar un cuadro de diálogo, debe escribir, en el evento Click del botón, la siguiente instrucción:
3. El botón Aceptar
Es el botón principal del cuadro de diálogo ya que es el que va a provocar la ejecución del programa.
En el evento Click del botón Aceptar, puede utilizar todos los valores de sus controles para iniciar los tratamientos en función
de los diferentes valores.
Encontrará un ejemplo del uso de este evento en la sección Los botones de opción.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Las casillas de verificación (CheckBox)
Las casillas de verificación (ChekBox) solo pueden devolver dos valores: marcada o no marcada (True o False). En cada
clic del usuario, el control pasa del estado marcado al estado no marcado, y viceversa.
Para agregar una casilla de verificación a su cuadro de diálogo, haga clic en el icono del Cuadro de
herramientas y haga clic y arrastre el ratón en el UserForm para hacer aparecer un control CheckBox.
En el siguiente ejemplo, la casilla de verificación permite activar el botón Aceptar solo cuando la casilla está marcada.
Me.CommandButton1.Enabled = False
End If
End Sub
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Las casillas de verificación son independientes entre sí: si en su cuadro de diálogo debe comprobar varias casillas de verificación,
debe comprobar todas las combinaciones posibles.
Por ejemplo, el siguiente cuadro de diálogo contiene cuatro casillas de verificación. Cada control puede tener dos
estados (True o False). En ese caso, habría que verificar los cuatro controles, por lo tanto, hay 24 = 16 combinaciones
posibles y similar número de verificaciones.
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Los botones de opción (OptionButton o botones radio)
A diferencia de las casillas de verificación que son independientes entre sí, los botones de opción (OptionButton)
están relacionados los unos con los otros.
Un grupo de botones de opción se utiliza para escoger una opción entre varias. Cuando el usuario seleccione un botón
de opción, los demás botones de opción se deseleccionarán.
Para agregar un botón de opción a su cuadro de diálogo, haga clic en el icono del cuadro de
herramientas y haga clic y arrastre el ratón en el UserForm para hacer aparecer un control OptionButton.
Para recuperar en su código el valor seleccionado, debe hacer un test en el valor True (valor cuando el botón está seleccionado)
para cada uno de los controles. Lo mejor es utilizar la instrucción Select Case y comprobar el valor
True.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Case Me.OptionButton4.Value
MsgBox Me.OptionButton4.Caption
Case Me.OptionButton5.Value
MsgBox Me.OptionButton5.Caption
End Select
End Sub
Cada vez que haga clic en el botón Aceptar, aparecerá un mensaje correspondiente al nombre (Caption) del control en un
cuadro de diálogo.
Para que los botones de opción actúen en conjunto, deben estar colocados en un continente que puede ser el
UserForm o un marco (Frame).
Un marco (Frame) permite delimitar una zona en su cuadro de diálogo. Permite agrupar visualmente los elementos, pero
también hacer cohabitar botones de opción para permitir seleccionar varios.
Encontrará este ejemplo de UserForm con dos marcos en el archivo del Ejemplo 19F2.
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Los cuadros de lista (o ListBox)
1. Presentación
Los cuadros de lista (ListBox) de un cuadro de diálogo permiten al usuario seleccionar un elemento entre una lista de
datos. El usuario no tiene la posibilidad de agregar o modificar los valores de una lista cuando el cuadro de diálogo
aparece al ejecutar el programa.
Para agregar un cuadro de lista a su cuadro de diálogo, haga clic en el icono del cuadro de
herramientas y haga clic y arrastre el ratón en el UserForm para hacer aparecer un control ListBox.
RowSource Para precisar el origen de los valores. Se puede tratar de celdas de una hoja de cálculo o de datos
transmitidos por un programa.
ListStyle Para agregar un icono delante de los datos (1) o mostrar únicamente los valores (0).
MultiSelect Para permitir seleccionar un solo valor (0) o varios (1). Puede realizar una selección múltiple
ya sea seleccionando cada valor pulsando al mismo tiempo la tecla [Ctrl], o haciendo una
selección pulsando la tecla [Mayús].
MatchEntry Para poder usar el teclado para acceder más rápidamente a los elementos de la lista.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
2. Manipular los datos de la lista
Recuperar el valor del elemento seleccionado en un cuadro de lista es más difícil que para otros controles. En primer lugar,
debe recuperar la posición del elemento seleccionado y después el valor correspondiente a este número en la lista.
Para recuperar el número correspondiente a la posición en la lista, utilice la propiedad ListIndex. Como para
las tablas en la memoria, el primer elemento de un cuadro de lista empieza siempre por el índice 0.
Val_Índice = Me.ListBox1.ListIndex
Para encontrar el valor seleccionado, utilice el índice del valor tal y como se indica en la línea de código
precedente e integre ese valor con el método List para mostrar el nombre del valor seleccionado.
Para este ejemplo, obtenemos el siguiente código en el evento Change del control ListBox:
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
En caso de una selección múltiple, debe hacer un bucle en todos los elementos de la lista y verificar cada uno de ellos
para saber si se han seleccionado o no.
Si retomamos el ejemplo anterior con una selección múltiple posible, puede visualizar los meses
seleccionados en un cuadro de diálogo tras haber hecho clic en el botón Aceptar.
El código es el siguiente:
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 3-
3. Alimentar una lista en el programa
En vez de rellenar su ListBox a partir de datos de una hoja de cálculo, puede alimentarla en el momento de cargar el
cuadro de diálogo. Así, puede agregar o suprimir elementos sin tener que abandonar el UserForm.
Por ejemplo, quiere crear una lista de los números pares del 0 al 10. Con el método AddItem, puede cargar sus
propios datos:
También puede suprimir elementos del cuadro de lista con el método RemoveItem; por ejemplo, puede eliminar de su
lista el elemento seleccionado haciendo clic en el botón Suprimir.
El código será:
Tras haber pulsado en el botón Suprimir, aparecerá su lista sin el elemento que acaba de eliminar.
- 4- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
El código de este ejemplo se encuentra en el archivo del Ejemplo 19G3.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 5-
Los cuadros combinados (ComboBox o menús desplegables)
Los menús desplegables (ComboBox) son los controles más utilizados son sencillos de utilizar pero también son los más
difíciles de codificar ya que debe gestionar el elemento seleccionado en la lista, pero también gestionar la adición del nuevo
elemento.
Los cuadros combinados combinan a la vez la selección de un elemento y la adición de un nuevo elemento como si el menú
desplegable fuera una zona de texto (TextBox). Los controles ComboBox no permiten la selección múltiple.
Para agregar un cuadro combinado a su cuadro de diálogo, haga clic en el icono del cuadro de
herramientas y haga clic y arrastre el ratón en el UserForm para hacer aparecer un control ComboBox.
RowSource Para precisar el origen de los valores. Se puede tratar de celdas de una hoja de cálculo o de datos
transmitidos por un programa.
ListStyle Para agregar un icono delante de los datos (1) o mostrar únicamente los valores (0).
MultiSelect Para permitir seleccionar un solo valor (0) o varios (1). Puede realizar una selección múltiple ya sea
seleccionando cada valor pulsando al mismo tiempo la tecla [Ctrl], o haciendo una selección
pulsando la tecla [Mayús].
MatchEntry Para poder usar el teclado para acceder más rápidamente a los elementos de la lista.
Para devolver el dato seleccionado en el menú desplegable, escriba el siguiente código en el envento Change del
control ComboBox:
Si permite la entrada en el cuadro combinado de un valor que no está en la lista, tendrá que gestionar un evento que agregue este
elemento a la lista inicial.
En el siguiente ejemplo, la columna A contiene cuatro nombres. Para que los usuarios puedan agregar un nombre en
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
esta lista, debe crear un botón Adición que recuperará el valor introducido por el usuario y agregará dicho valor a la lista
inicial.
Call UserForm_Initialize
End Sub
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Síntesis
Como muestran los ejemplos, las posibilidades que ofrecen los distintos controles son numerosas y las
manipulaciones en los datos transmitidos por cada control son muy diferentes.
El siguiente ejemplo le muestra cómo inicializar todos los controles de su cuadro de diálogo. Como puede comprobar, una
zona de texto no se inicializa como un botón de opción, ni como un cuadro de lista:
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Introducción
En VBA, un error se traduce siempre por la interrupción del programa. Sin embargo, todos los errores no tienen
porqué serlo para usted. Por ejemplo, si quiere seleccionar una hoja que no existe aún, su programa le indicará un error
pero para usted, es precisamente una información para crear la nueva hoja de cálculo o no.
Según la naturaleza del error, el lenguaje VBA devolverá un número de anomalía. En el anexo (sección Lista de
códigos de error transmitidos por Visual Basic) encontrará la lista de anomalías y su significado. A continuación, en
función de los códigos devueltos, podrá realizar tratamientos específicos.
Para evitar que su programa se bloquee por un error, debe integrar una redirección en el procedimiento.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Las instrucciones para la gestión de errores
Antes de ver cómo gestionar los errores en un programa, vamos a conocer las funciones que nos permitirán tratarlos.
1. On Error
Para indicar que desea gestionar los errores en un procedimiento, va a escribir en su procedimiento la instrucción
On Error. Esta función sola no tiene ninguna utilidad, normalmente hay que añadirle la instrucción GoTo.
2. La instrucción Resume
La instrucción Resume indica que el programa se retomará en la línea que ha generado el error.
Si desea continuar su programa tras la línea que ha provocado el error, debe escribir la instrucción Resume Next.
4. La instrucción Err
La instrucción Err permite recuperar el número de la anomalía. Con esta instrucción se pueden administrar varios tipos
de anomalía en su programa.
Esta propiedad devuelve el texto del error. Puede utilizarla en un mensaje que se mostrará en la pantalla:
5. GoTo
La instrucción GoTo permite, en caso de que se detecte un error durante la ejecución, ir, en el mismo procedimiento, a un bloque
de código para tratar la o las anomalías encontradas (ver los ejemplos a continuación).
6. GoTo 0
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
La instrucción GoTo 0 anula las instrucciones específicas que haya escrito para tratar los errores y deja que Excel
gestione los errores deteniendo el programa.
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Redirección de errores
Gracias a las instrucciones anteriores, puede transformar sus programas para tener en cuenta los errores.
1. Ejemplo 1
Pongamos por caso que crea un libro de síntesis anual en el que crea cada mes una nueva hoja que recoge la
actividad del mes corriente. Cada vez que abra el programa quiere que el documento se abra en la hoja del mes actual.
Sub Auto_Open()
Dim Nombre_Hoja as String
Nombre_Hoja = Format(Date, "mmmm-
yyyy") Sheets(Nombre_Hoja).Select
End
Sub
El problema es que cada nuevo mes, el libro querrá colocarse en una hoja que no existe. Por lo tanto aparecerá el
siguiente mensaje:
En primer lugar, vamos a indicar que las anomalías las gestiona el módulo con la instrucción On Error y después, al
final del procedimiento, vamos a escribir el código que añadirá la nueva hoja.
Sub Auto_Open()
Dim Nombre_Hoja as String
On Error Goto Gestión_Error
Nombre_Hoja = Format(Date, "mmmm- yyyy")
Sheets(Nombre_Hoja).Select
Gestión_Error:
Instrucción
End Sub
En caso de una redirección, la instrucción Goto irá obligatoriamente seguida de un nombre de etiqueta. A continuación,
debe hacer referencia a esta etiqueta al final del procedimiento. De hecho, esta etiqueta es similar a un subprograma, por lo
tanto es indispensable escribirla al final del procedimiento para distinguir su programa de la gestión de errores.
En la etiqueta Gestión_Error, vamos a escribir el código que permita agregar una nueva hoja. Y, para
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
renombrar la hoja, vamos a utilizar la misma variable ya que estamos en el mismo procedimiento.
Sub Auto_Open()
Dim Nombre_Hoja as String
On Error Goto Gestión_Error
Nombre_Hoja = Format(Date, "mmmm-
yyyy") Sheets(Nombre_Hoja).Select
Gestión_Error:
Sheets.Add After:=Sheets(Sheets.Count)
ActiveSheet.Name = Nombre_Hoja
End
Sub
En este ejemplo, se añadirá una nueva hoja pero el programa se detendrá justo tras la línea en la que se renombra a la
hoja. Para volver al programa principal, debemos volver a añadir la instrucción Resume para volver a la línea que ha
provocado la anomalía o Resume Next para volver a la línea siguiente.
Por el contrario, cuando el código principal (fuera de la etiqueta) haya acabado, el programa continuará leyendo las
instrucciones, incluso si no hay error. Para evitar que estas líneas se traten, debe hacer un test en el número del código
del error.
Sub Auto_Open()
Dim Nombre_Hoja as String
On Error Goto Gestión_Error
Nombre_Hoja = Format(Date, "mmmm-
yyyy") Sheets(Nombre_Hoja).Select
Gestión_Error:
If Err.Number = 9 Then
Sheets.Add After:=Sheets(Sheets.Count)
ActiveSheet.Name = Nombre_Hoja
Resume
End If
End Sub
También puede detener el programa justo antes de la etiqueta agregando la instrucción Exit Sub para salir
instantáneamente de su procedimiento.
Sub Auto_Open()
Dim Nombre_Hoja as String
On Error Goto Gestión_Error
Nombre_Hoja = Format(Date, "mmmm- yyyy")
Sheets(Nombre_Hoja).Select
Exit Sub
Gestión_Error:
If Err.Number = 9 Then
Sheets.Add After:=Sheets(Sheets.Count)
ActiveSheet.Name = Nombre_Hoja
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Resume
End If
End Sub
2. Ejemplo 2
En la parte que trata los errores, puede realizar varias acciones en función del número de anomalía. Para ello, basta con
hacer un test en el número de anomalía ( Err.Number) y, para cada valor, se realizarán instrucciones
específicas.
Gestión_Error:
Select Case Err.Number
Case 9
Instrucción
Case 1004
Instrucción
Case Else
MsgBox "Otro Error " & Err.Number & " " & Err.Description
End Select
3. Ejemplo 3
En lugar de indicar en su procedimiento que se conecte a una etiqueta para tratar los errores, también puede precisar
que el error se pase sin interrumpir la ejecución del código.
Para ello, puede, desde el principio del procedimiento (o función), utilizar la instrucción On Error pero, en este caso,
sustituya la instrucción Goto por Resume Next.
El nombre de la hoja probada ( sname) se coloca como parámetro y este nombre se transmite a una variable
Objeto_Hoja declarada en Objeto.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 3-
Tipos de variables
Boolean La variable solo puede tomar dos valores: True o False (o bien 0 o 1).
Byte Este tipo se utiliza para la manipulación de datos binarios. Un dato binario está representado por un
número de 8 bits (es decir, 8 cifras). Cada bit es un 0 o un 1. Un valor de tipo Byte puede tener un
valor entre 0 y 255. Si el contenido de un valor superase los 255, el programa se detendría.
Date El tipo Date posee todas las fechas comprendidas entre el 1 de enero del año 100 y el 31 de diciembre
de 9999, de las 0:00:0 0 a las 23:59:59 horas de cada día. Este tipo se encuentra en la tipología de las
variables ya que los días o los meses no se añaden como cifras.
Currency El tipo Currency represent a todos los datos monetarios: son números comprendidos entre
922337203685477,580 8 y 922337203685477,5807.
Integer El tipo Integer devuelve un número entero comprendid o entre 32768 y 32767. Este tipo de variable
se utiliza mucho para hacer bucles en fila o en columnas (con la condición de no superar las 32767 filas).
Long Es una extensión del tipo Integer. Los valores están comprendidos entre 2147483648 y
2147483647.
Single El tipo Single representa valores decimales. Los valores posibles están comprendidos entre
3,402823 x 10 38 y 1,401298 x10 45 para los valores negativos y entre 1,401298 x 10 45 y
3,402823 x 10 38 para los valores positivos.
Double El tipo Double representa los valores de números con coma flotante de doble precisión. Los valores
posibles están comprendidos entre 1,79769313486231 x 10 308 y 4,94065645841247 x10 324 para los
números negativos y entre 4,94065645841247 x 10 324 y 1,7976931348623 x
10 308 para los números positivos. Más allá de toda consideración de ocupación en la memoria, es
un tipo al que hay que dar prioridad.
String Las cadenas de caracteres (String en inglés) son las expresione s de texto. Estas no se pueden utilizar
para cálculos matemático s u operaciones lógicas. De hecho, estas expresiones son la concatenación de
varios caracteres. Una cadena de caracteres no puede contener más de 2.000 millones de caracteres
aproximadamente (¡es más que suficiente!).
Variant El tipo Variant es un tipo que agrupa todos los demás tipos citados anteriormente. Es una especie de
"trastero" muy práctico, pero a veces puede parecer desconcertante.
Object El tipo Object tiene como valor el de una clase. Una clase es un modelo que posee propiedades y métodos.
En Excel, se consideran como objeto las celdas, filas, columnas, hojas de cálculo, gráficos, libros, etc.
Estas variables se utilizan en colecciones de objetos.
LongLong Tipo de datos de 8 bytes únicamente disponible en los sistemas de 64 bits. De tipo numérico. Números
enteros comprendidos entre 9 223 372 036 854 775 808 y 9 223 372 036 854 775 807. LongLong es un
tipo únicamente declarado válido en las plataformas de 64 bits.
LongPtr Tipo de datos de variable de 4 bytes en las versiones de 32 bits y de 8 bytes en las versiones de
64 bits de Office 2010. Se trata del método recomendado para declarar un puntero o un controlador para un
código nuevo, pero también para un código heredado si este debe ejecutarse en la versión de Office de 64
bits.
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Colección de objetos
Aquí presentamos la lista de colecciones de objetos más comunes en Excel y sus campos de aplicación. Una colección
de objetos puede aplicarse en un libro, a una hoja de cálculo, a gráficos.
AllowEditRanges Representa el conjunto de celdas no cerradas en una hoja de cálculo (cuando la hoja está
protegida).
Areas Para una selección de celdas, Areas representa el conjunto de celdas de esta selección.
Esta colección se usa básicamente para la propiedad Count que devuelve el número de celdas de
la selección.
CalculatedMembers Solo se aplica a una tabla cruzada dinámica: representa el conjunto de elementos
calculados en la tabla cruzada dinámica.
Charts Representa el conjunto de curvas, barras, etc. que representan las series de datos en un gráfico.
DataLabels Representa el conjunto de etiquetas de sus series de datos (se aplica únicamente a los
gráficos).
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
Lista de constantes
Lista de constantes para ubicarse en las rutas de acceso estándar de Windows.
&H5 = My Documents
&H2E = \Documents
&H6 = \Favorites
&H8 = \Recent
&H9 = \SendTo
&H10 = \Desktop
&H15 = \templates
&H17 = \Programs
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-
&H18 = \Startup
&H19 = \Desktop
&H1B = \PrintHood
&H25 = GetSystemDirectory()
&H28 = \
&H2D = \Templates
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
&H37 = My Video folder for all users
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 3-
Lista de códigos de error transmitidos por Visual Basic
6 Desbordamiento.
7 Sin memoria.
51 Error interno.
53 No se encuentra el archivo.
55 Archivo ya abierto.
58 El archivo ya existe.
61 Disco lleno.
67 Demasiados archivos.
68 Dispositivo no disponible.
70 Permiso denegado.
71 Disco no preparado.
- 1-
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
93 Cadena modelo no válida.
451 El procedimiento Let de la propiedad no está definido y el procedimiento Get no ha devuelto un objeto.
- 2- © Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella
Lista de caracteres no imprimibles
0 Carácter nulo
1 Inicio de encabezamiento
2 Inicio de texto
3 Fin de texto
4 Fin de transmisión
6 Acuse de recibo
7 Timbre
8 Retroceso
9 Tabulación horizontal
10 Salto de línea
11 Tabulación vertical
12 Salto de página
13 Retorno de carro
14 Mayúsculas fuera
15 En mayúsculas
22 Síncrono en espera
24 Cancelar
26 Sustituto
27 Escape
28 Separador de archivo
29 Separador de grupo
30 Separador de registro
31 Separador de unidad
© Éditions ENI – Todos los derechos reservados – Copia personal de Omar Enrique Antequera Armella - 1-