Sie sind auf Seite 1von 218

VBA EXCEL 2010 DESARROLLE UNA APLICACIÓN EN FORMA PROFESIONAL

Índice
 Información
o Título, autor...
 Introducción
o Introducción
o Descarga de los ejemplos del libro
 Excel y la programación
o Los objetivos
o Las bases del lenguaje VB
o Organización del código y metodología
o El entorno de desarrollo en Excel
 Primeras manipulaciones y gestión de candidatos
o Objetivos
o La gestión de los libros y las hojas
o Llamada de procedimientos en la herramienta y gestión del código
o VBA y la gestión de datos cargados
o Visualización de estadísticas por habilidades con gestión de errores en el
procedimiento
o Copias de seguridad del proyecto Gestión de perfiles
 Transformación de la herramienta en ejecutable
o Objetivos
o Formularios para gestionar los candidatos
o Presentación del objeto Formulario y de los principales controles del
cuadro de herramientas
o Creación de subtotales en la lista de inscritos
o La gestión de estado de los miembros
 Implementación del planning de los candidatos
o Objetivos
o Extensión de los procesos de navegación al conjunto de la aplicación
Gestión de perfiles
o Integración de la plantilla para la creación de trabajos
o Gestión de las asignaciones y de las fechas de los trabajos
 Gestión de la aplicación con una base de datos
o Objetivos
o La base de datos BDD_Agencia y su entorno
o La gestión de los datos de la agencia
 Proteger la aplicación Gestión de Perfiles
o Objetivos
o La contraseña del IDE
o El control de las entradas del usuario
o La protección de las hojas en la aplicación
o La recuperación de los permisos de usuario y la navegación en la
aplicación

VBA Excel 2010Desarrolle mediante un ejemplo una aplicación


profesional
El libro VBA Excel 2010 se dirige a usuarios avanzados de Excel que se quieran introducir en la
programación VBA. El autor propone el desarrollo en VBA de una herramienta de gestión de
una empresa de trabajo temporal; todas las respuestas y soluciones propuestas se pueden
adaptar, por supuesto, a otros desarrollos de aplicaciones de carácter profesional.
En primer lugar, el autor presenta la teoría del lenguaje de programación VBA y describe el
entorno de trabajo. A lo largo del resto de capítulos, el autor desarrolla la aplicación: gestión
de los datos, generación de un gráfico de asignación de tareas, puesta en marcha y
protección.
En el transcurso del libro se proponen al lector numerosos consejos vinculados a la gestión de
un proyecto y a la organización del código.
Los ejemplos de código se pueden descargar de la web www.ediciones-eni.com.

Los capítulos del libro:


Introducción – Excel y la programación – Primeras manipulaciones y gestión de los candidatos
– Transformación de la herramienta en ejecutable – Implementación del planning de los
candidatos – Gestión de la aplicación con una base de datos – Proteger la aplicación Gestión de
perfiles

Ludovic LANNOY

Ludovic Lannoy es Ingeniero desde hace más de 10 años. Como parte de su trabajo,
desarrolla aplicaciones en VB o VBA para responder a las necesidades de empresas muy
diversas. A través de este libro proporciona al lector una base muy eficaz para introducirse en
el desarrollo VBA.

Introducción

Introducción
Esta obra se dirige principalmente a los usuarios avanzados de Excel. Efectivamente,
antes de atreverse con la programación es preferible conocer la parte de usuario y las
diferentes funcionalidades a disposición de los usuarios a través de los menús. Esto no
es excluyente pero los programas escritos en Excel se basan en las funcionalidades de
esta hoja de cálculo adaptándolas a las necesidades específicas de los usuarios. Además,
sin ser un experto, deberá dominar los menús más utilizados como los filtros, las tablas
dinámicas, las ordenaciones... Debe ser capaz de insertar funciones o elaborar fórmulas
de cálculos más o menos elaboradas.
Este libro está destinado también a los programadores con experiencia como usuarios de
VB (Visual Basic) que pensaban que podían librarse de un estudio previo del lenguaje
VBA (Visual Basic for Application) aplicado en el entorno de desarrollo específico de
Excel.

La programación en VBA le va a permitir crear rápidamente y fácilmente aplicaciones


profesionales. Es un lenguaje sencillo con el que puede ir más allá de los menús de
Excel y crear programas a medida. Aumentará su productividad automatizando tareas
costosas en tiempo, repetitivas y aburridas.

No es necesario tener un perfil científico para escribir código. Basta con un poco de
sentido común y sobre todo de un buen conocimiento funcional del dominio de la
aplicación a desarrollar. La programación no es exclusiva de los informáticos.

El caso práctico presentado por este documento es el desarrollo de una aplicación


dedicada a la gestión de candidatos por una empresa de trabajo temporal. Esta
herramienta permitirá preguntar a los diferentes recursos para responder a las peticiones
de asignación de personal para trabajos, solo o en equipo. Esta aplicación siempre
deberá ser capaz de hacer una restitución de la disponibilidad de los inscritos en la
agencia. Un horario permitirá efectuar asignaciones por trabajo. Los datos se
gestionarán en una base de datos de tipo Access.

El libro está organizado en torno a varios capítulos.

El primer capítulo, Excel y la programación, está dedicado a algo de teoría,


indispensable para la comprensión del lenguaje VB y de la programación VBA
resultante. Se hará una presentación del entorno de trabajo que será el suyo.

El segundo capítulo, Primeras manipulaciones y gestión de los candidatos, se iniciará el


desarrollo de la herramienta de gestión para la agencia de trabajo temporal. Las
primeras manipulaciones permitirán comenzar a gestionar los datos necesarios para el
proyecto.

El tercer capítulo, Transformación de la herramienta en ejecutable, se creará realmente


la herramienta que se convertirá en una aplicación completa como las que se desarrollan
en Visual Basic.net o con otras herramientas CASE.

El cuarto capítulo, Puesta en marcha del horario de los candidatos, tratará de la puesta
en marcha de un horario en forma de un histograma de asignaciones de candidatos por
trabajo.

El quinto capítulo, Gestión de la aplicación con una base de datos, establecerá los
intercambios con la base de datos.

El sexto y último capítulo, Proteger la aplicación Gestión de perfiles, tratará de la


implementación de la protección de la aplicación.
Descarga de los ejemplos del libro
Los numerosos ejemplos se pueden descargar de la web de ediciones ENI:
www.ediciones-eni.com

Esto concierne a archivos de datos, el código contenido en los módulos y la base de


datos.

Excel y la programación
Los objetivos
Este capítulo del libro es esencialmente teórico. De hecho, antes de comenzar con la
programación, hay que asimilar ciertas bases como la sintaxis del lenguaje o las reglas
de escritura de código.

Para esto, vamos a estudiar el lenguaje VB en el que se basa VBA.

A continuación se describe el entorno de desarrollo.

Por último, durante todo el capítulo se irá recordando la manera de organizar el código y
el progreso general del proyecto.

Las bases del lenguaje VB


El lenguaje Visual Basic proviene directamente de BASIC. Es también la base del
lenguaje VBA. Este último se articula alrededor de VB con características vinculadas a
la herramienta de Office a la que esté asociada. En el ámbito de nuestro estudio, se trata
de la herramienta Excel.

1. Las variables
Las variables sirven para almacenar y manipular información. La que puede variar
durante la ejecución tiene el nombre de variables.

Las variables se declaran en los procedimientos contenidos en los módulos o


formularios del programa.

a. La declaración implícita o explícita

El lenguaje VB puede crear automáticamente variables sin declaración previa dándole el


tipo relacionado con su utilización. Se trata de una declaración implícita. Sin embargo,
se aconseja declarar estas variables antes de utilizarlas por razones de rigor y legibilidad
del código. Esta declaración de variables es entonces de tipo explícito. Para hacer
obligatoria la declaración de variables, es necesario configurar el entorno de desarrollo.
1. Utilice el menú Herramientas - Opciones y en la pestaña Editor, marque la
casilla Requerir declaración de variables.

La línea de código Option Explicit aparecerá ahora en la sección (General) / (Declaraciones) de


sus módulos o de sus formularios. Si utiliza una variable no declarada en su código, la
compilación del programa retorna un error.

b. Los diferentes tipos de variables

Cuando se crea la variable, se le atribuye un tipo con la instrucción Dim. Ejemplos: en


el caso de un tipo alfanumérico, el tipo es String.

Para un número pequeño, el tipo es Integer.

Para asignar un valor a una variable o a una propiedad hay que usar el símbolo =.
Vea la siguiente tabla de resumen de los diferentes tipos de variables:

La denominación de variables responde a reglas muy estrictas. El nombre permite saber


inmediatamente si se trata de una variable. El tipo de variable también debe ser evidente. Por
último, el nombre se refiere al valor almacenado. En el ejemplo IntEdad, es fácil ver que se
trata de una variable de tipo Integer (Prefijo Int) relacionada con una edad. Para poner prefijo
a una variable, se utiliza el diminutivo de su tipo. Finalmente, hay que fijarse en que el nombre
de las variables no se corresponda con una palabra reservada de VB.

Los valores alfanuméricos van siempre entre dobles comillas ("....").

c. La duración y el ámbito de una variable

La duración de una variable con la instrucción Dim se limita a la ejecución del


procedimiento en el que se encuentra. De hecho, en cada ejecución se reinicializa. Si
quiere conservar el valor asignado, debe utilizar la instrucción Static en la declaración.
La duración será la de la aplicación.
El ámbito de una variable depende de dónde y cómo se declara. Una variable declarada en un
procedimiento sólo se puede utilizar en ese procedimiento. Si la declara en la zona (General) /
(Declaraciones) del módulo bajo la línea de código Option Explicit, será accesible por el
conjunto de los procedimientos del módulo.

Pero puede que lo necesite para el conjunto de módulos de su aplicación. En este caso
utilice siempre en la cabecera del módulo Public en lugar de Dim.

Si por el contrario desea que no sea accesible por otros módulos hay que declararla
como Private.

d. Las constantes

Las constantes se parecen a las variables pero como su nombre indica no se pueden
modificar. Además, la asignación de un valor a una constante se hace en el momento de
su declaración y no durante la ejecución de la aplicación.

El interés de una constante es que conserva su valor durante toda la duración del
programa. Es inútil pues, declarar una cadena de caracteres compleja, como la ruta de
acceso (ver arriba) o una clave de identificación, en diferentes sitios del código.
Igualmente, si hay que modificar esta cadena, basta con hacerlo una sola vez a nivel de
la declaración de la constante.

2. Los operadores
Para efectuar operaciones sobre los datos, Visual Basic proporciona operadores. Éstos
se utilizan en función del tipo de datos utilizados.

Existen tres grandes grupos de operadores: los operadores de comparación, los


operadores lógicos y los operadores matemáticos.
a. Los operadores de comparación

b. Los operadores lógicos


c. Los operadores matemáticos

& y + permiten la concatenación de caracteres pero el segundo es ambiguo ya que VB


intenta primero hacer una suma.

Ponga atención en el orden de los operadores ya que existe una prioridad. En una
fórmula compleja, la prioridad absoluta la dan los paréntesis (). Los operadores de
comparación tienen la misma prioridad y se evalúan en su orden de aparición, de
izquierda a derecha. Por el contrario, los operadores lógicos y matemáticos se evalúan
en el siguiente orden: ^, -, * y /, \, MOD, + y por último -.

3. Estructuras de decisión y bucles


Las instrucciones de un programa se desarrollan normalmente de manera secuencial con
intervalos regulares para tomar decisiones entre varias opciones, esto son las
condiciones o estructuras de decisión. A veces, también es necesario provocar
repeticiones de acciones, esto son los bucles.

a. Las estructuras de decisión

La estructura de una condición sencilla con los términos If (si), Then (entonces) y End
If (fin del si) es la siguiente:

If <Condición> Then
<Instrucciones>
End If

El programa comprueba si una condición se cumple para efectuar una secuencia de


código. Si no se cumple, la secuencia de código se ignora.
El código se puede escribir en una sola línea si sólo hay una instrucción a ejecutar.
Entonces no es necesario escribir End If para cerrar la condición.

If <Condición> Then <Instrucción>

Si la condición no se cumple, es posible encadenar otras condiciones con los términos


Else (sino) o ElseIf (sino si) que ofrecen otras secuencias de código que se ejecutarán si
no se ejecuta la primera.

If <Condición_1> Then
<Instrucciones_1>
ElseIf <Condición_2> Then
<Instrucciones_2>
Else
<Instrucción_3>
End If

Si la <Condición_2> se cumple <Instrucciones_2> se ejecuta y el programa sale de la


condición. <Instrucción_3> se ejecuta por defecto si todas las condiciones precedentes
no se cumplen. No hay límite en el número de condiciones ni en su nivel de
anidamiento.

En el siguiente ejemplo, probamos dos individuos para definir cual es el mayor de los
dos. Para que esta comparación tenga sentido, hace falta que al menos uno de los dos
individuos haya nacido.

El resultado se visualiza en pantalla a través de un cuadro de diálogo.


Por razones de legibilidad, es necesario aplicar ciertas reglas de escritura. Hay que
sangrar el código. Los diferentes bloques se desplazan hacia la derecha en sus
condiciones. Para espaciar el código, no dude en saltar líneas.

Es necesario insertar comentarios para explicar las diferentes articulaciones de


código y los bloques complejos, especialmente en los algoritmos. Estos comentarios
serán útiles para todos, ya que no es siempre fácil sumergirse en un programa escrito
meses antes para hacer correcciones o evolutivos. Por último, son también un buen
medio de ganar legibilidad. Para comentar un línea, basta con poner una comilla simple
(’) en el inicio de la misma línea.

Con Select Case, existe otra manera de estructurar las condiciones especialmente si hay
varias respuestas posibles. Se ejecuta más rápido que con If y el código es más legible.

Select Case <Expresión>


Case <Lista de Expresiones_1>
<Instrucciones_1>
Case <Lista de Expresiones_2>
<Instructiones_2>
Case Else <Lista de Expresiones_3>
<Instrucciones_3>
End If

Vea un ejemplo de código con este test condicional.

b. Los bucles

Hay varios tipos de bucles para repetir una instrucción un determinado número de
veces.

For - Next
For <Variable Contador> To <Variable Bucle>
<Instrucción>
Next
<Variable Contador> permite definir el valor de inicio y <Variable Bucle> indica el
número de veces que se ejecutará la secuencia de código.

Vea un ejemplo:

Es posible añadir al lado de <Variable Bucle> una <Variable Incremento> que modifica
el valor de incremento. De hecho, este valor por defecto es 1. Con For i = 1 To 10 Step
2, sólo se producen 5 repeticiones en el bucle y el resultado mostrado por MsgBox será
entonces 32.

En el código anterior, la variable i no tiene el prefijo Int. De hecho, en programación


es habitual utilizar directamente las letras i, j o k para alimentar contadores.

La variable IntResult está limitada a la capacidad del tipo Integer, un número entero
entre -32 768 y +32 767. Además, si nuestro bucle se ejecuta 15 veces, el resultado
mostrado será 32 768. Este número rebasa la capacidad de una variable de tipo Integer.
Es posible optar por un tipo Long, un número entero entre -2 147 483 648 y
2 147 483 647. Pero es mejor utilizar la instrucción Exit que permite interrumpir una
secuencia de código. En el ámbito de un bucle For - Next, hay que escribir Exit For.

Una vez que la variable i alcanza el número 15, la ejecución del bucle se para y se
ignora la instrucción IntResult = IntResult * 2.

While - Wend

Es un bucle muy simple que repite las instrucciones mientras la condición de inicio sea
verdadera.

While <Condición de inicio>


<Instrucción>
Wend

El siguiente ejemplo hace emitir un sonido al ordenador mientras la variable contador


no sea 20.
La variable i no se ha alimentado. Por defecto estará a 0 porque es de tipo Integer. Para
un tipo String será igual a " " e igual a False para un tipo Boolean.

No hay que olvidar incrementar el contador en este tipo de bucle, ya que se puede
crear un bucle infinito.

Do - Loop

Es un bucle un poco más elaborado que el anterior. Repite las instrucciones mientras
que (Do While) o hasta que (Do Until) la condición de inicio sea cierta.

Do While o Do Until <Condición de Inicio>


<Instrucción>
Loop

Vea los dos ejemplos que conducen a dos resultados diferentes: 21 con While y 20 con
Until. Esta diferencia se explica por el hecho de que la condición debe ser verdadera
para empezar con While y falsa para empezar con Until. La regla se invierte para salir
de la condición. Debe ser falsa con While y verdadera con Until.

Para obtener un resultado idéntico, sería necesario, por ejemplo, modificar la primera línea de
código del While : Do While i <= 19. Así, es posible utilizar las dos formas. En función del
contexto, convendrá utilizar más uno u otro.

Hay que resaltar que después del primer bucle hay que reinicializar la variable i
porque ya se ha incrementado y es importante no acumular el valor que ya tiene con el
incremento del siguiente bucle. Este es un concepto importante que conviene recordar
en relación con el uso de variables globales visitadas por una multitud de
procedimientos en el programa.
Estos bucles pueden no ser ejecutados si en el inicio la <Condición de Inicio> no es
verdadera. No es el caso del siguiente bucle que al contrario que los anteriores se
ejecuta al menos una vez.

Do
<Instrucción>
Loop While o Do Until <Condición de Inicio>

Para interrumpir estos bucles, puede utilizar la instrucción Exit Do.

4. Concepto de propiedades y de métodos


El lenguaje VB se compone de multitud de objetos. Propiedades y métodos se asocian a
todos los objetos. Una propiedad es una característica del objeto. Un método representa
una acción posible sobre el objeto y determina su comportamiento.

Consideremos por ejemplo un objeto llamado Perro. Sus propiedades podrían ser su
tamaño, su peso o el color del pelo. Los métodos relacionados serían ladrar, comer o
llevar un palo.

En el ámbito de VB, existen objetos con propiedades y métodos predefinidos por los
creadores del lenguaje.

Consideremos ahora un ejemplo directamente vinculado a Excel. El objeto Sheets


corresponde a la hoja de un libro.

La propiedad Caption del objeto recupera el nombre de esta hoja en el libro (Hoja1 u
otro). Del mismo modo, Visible define si esta hoja se muestra o se oculta (la propiedad
está entonces a True o False).

En el siguiente ejemplo, la hoja Hoja1 está oculta.

El método Add permite añadir una hoja al libro. Con Move puede desplazar esta hoja y
modificar su posición.

Existen numerosas propiedades y métodos para cada objeto utilizado en un programa.


Algunas se encuentran en diferentes objetos (el nombre, el color...). Ocurre igual con los
controles a insertar que estudiaremos un poco más adelante en el libro (véase el capítulo
Transformación de la herramienta en ejecutable - sección Formularios para gestionar los
candidatos). Es imposible querer conocerlas todas. Memorice las más comunes, pero
deberá inspeccionar en VBA para descubrir aquéllas que se adapten mejor a sus
programas.
Aparte de los objetos predefinidos del lenguaje VB, un usuario experimentado puede
crear sus propios objetos con las propiedades y métodos que necesite. Podrá hacerlo con
módulos de clase. Este es uno de los principios básicos de la programación orientada a
objetos pero no es el propósito de este libro.

5. Los procedimientos
Los procedimientos y las funciones agrupan secuencias de código a ejecutar. Permiten
descomponer el código en sub-programas más fáciles de comprender y mantener. Estos
procedimientos o funciones son reutilizables en todo el programa.

a. Los procedimientos

Los procedimientos se componen de un cierto número de instrucciones colocadas y


ejecutadas unas después de otras pasando a la línea siguiente cada vez.

Consideremos como estructurar un procedimiento.

Public o Private Sub Nombre_Proceso (Parámetros as Type)


<Instrucciones>
End Sub

El procedimiento se declara como Public o Private, lo que determina el ámbito de


aplicación en el programa. Las reglas son las mismas que para la declaración de
variables (véase el capítulo Excel y la programación - sección Las variables). Private
limita la disponibilidad sólo a los procedimientos del módulo de origen mientras que
Public la hace accesible a todo el programa. A continuación, viene la palabra Sub
seguida del nombre. La denominación de su procedimiento es importante porque
permite dar una idea inmediata sobre el código que contiene. End Sub cierra el
procedimiento después de la última instrucción. Es posible pasar parámetros con su
tipo.

Además, Exit Sub permite salir en el transcurso de la ejecución del procedimiento.

Un procedimiento puede estar vinculado a un evento pero también puede ser llamado
por una instrucción en cualquier lugar del programa. Se trata entonces de un
procedimiento general.

Consideremos un ejemplo de encadenamiento de procedimientos que calculan la parte


de IVA de una cantidad en Euros.
En el ejemplo anterior, Llamado_TxTVA() llama al procedimiento Calculo_IVA()
pasándole los parámetros o argumentos esperados, en este caso la cantidad y el
porcentaje para el cálculo. Call no es obligatorio para la llamada del procedimiento pero
ayuda a la legibilidad del código haciendo la llamada al procedimiento más visible en
una lectura posterior: Call Calcul_IVA(400, 5).

La variable IntResult que no forma parte de los argumentos pasados al llamar al


procedimiento se declara al inicio del bloque de código.

Si la cantidad o el porcentaje de IVA es 0, es imposible efectuar los cálculos y el


procedimiento se interrumpe: If IntCantidad <= 0 Or IntIVA <= 0 Then Exit Sub.

Después de ejecutar la secuencia de código, el resultado visualizado para el usuario es el


siguiente:

La declaración de un procedimiento es por defecto Public como en el caso del segundo


procedimiento Calculo_IVA.

b. La programación orientada a eventos

Una programación es orientada a eventos cuando la secuencia de código de los


procedimientos y funciones está vinculada a un evento. En efecto, cada control del
lenguaje VBA está dotado de eventos propios que pueden desencadenar los
procedimientos de evento que tiene asociados.
Tomemos por ejemplo el clic del ratón de un usuario sobre el botón de un formulario.
Esta acción conlleva una reacción del programa si el evento Click del botón está
asociado a un procedimiento de evento.

De este modo, en el siguiente ejemplo, el evento Click del botón CommandButton1


conlleva el cierre del libro.

Un evento también puede provocarlo el sistema sobre un objeto Excel. En el caso la


apertura de un libro, existe un evento Open asociado al objeto Workbook que activa un
procedimiento asociado al abrir el libro.

En el siguiente ejemplo, se carga un formulario cuando el usuario abre el libro.

Evidentemente, sólo hay que escribir código en los eventos útiles para la aplicación.
Este código se ejecutará cada vez que el o los evento(s) asociado(s) se desencadene(n)
por parte del usuario o del sistema.

Existen eventos específicos en cada herramienta de Office como es el caso de ciertos


eventos que utilizaremos en el ámbito de nuestro estudio de VBA asociado a Excel.

c. Las funciones

Al contrario que los procedimientos, la función devuelve un resultado. Desde el punto


de vista de la estructura, es casi idéntica a un procedimiento clásico. La instrucción Sub
se sustituye por Function y el tipo de valor devuelto se declara después de la declaración
de los parámetros esperados.

Public o Private Function Nombre_Funcion (Parámetros as Tipo) as Tipo


<Instrucciones>
End Function

Volvamos al ejemplo utilizado por el procedimiento con una función.


La visualización del resultado se hace en el procedimiento de llamada de la función ya
que el valor se le devuelve directamente en este procedimiento. La instrucción Exit
Function conlleva la salida de la función sin ejecutar la totalidad del código.

6. Las funciones integradas de VB


Del mismo modo que existen funciones integradas en Excel, el lenguaje VB propone
multitud de funciones que se pueden agrupar en grandes categorías. No es necesario
conocerlas todas. Pero antes de empezar con algoritmos complejos, hay que preguntarse
si no hay una función integrada que solucione nuestras necesidades.

Al igual que en un procedimiento función (véase el capítulo Excel y la programación -


sección Los procedimientos), la función integrada espera parámetros y devuelve un
valor de retorno.

Las secciones siguientes presentan una muestra de estas funciones.

a. La gestión de tipos de datos

CBool: convertir un dato dado por parámetro en tipo Boolean.

CCur: convertir un dato dado por parámetro en tipo Currency.

CDate: convertir un dato dado por parámetro en tipo Date.

CDbl: convertir un dato dado por parámetro en tipo Double.

CInt: convertir un dato dado por parámetro en tipo Integer.

CLng: convertir un dato dado por parámetro en tipo Long.

CSng: convertir un dato dado por parámetro en tipo Single.

CStr: convertir un dato dado por parámetro en tipo String.

Val: convertir una cadena de caracteres en datos numéricos.


b. Test de variables

IsDate: devuelve un valor booleano verdadero (True) si el dato pasado por parámetro es
de tipo Date.

IsEmpty: devuelve un valor booleano verdadero (True) si el dato pasado por parámetro
no ha sido inicializado.

IsNull: devuelve un valor booleano verdadero (True) si el dato pasado por parámetro
contiene el valor Null.

IsNumeric: devuelve un valor booleano verdadero (True) si el dato pasado por


parámetro es de tipo numérico.

IsObject: devuelve un valor booleano verdadero (True) si el dato pasado por parámetro
es de tipo Object.

c. Operaciones con cadenas de caracteres

Asc: devuelve el código ASCII del primer carácter de la cadena pasada por parámetro.

Chr: devuelve el carácter del código ASCII que se ha pasado por parámetro.

Format: Da formato para presentar datos de tipo fecha, numérico o cadena de caracteres.

Instr: búsqueda de una cadena de caracteres en otra cadena de caracteres y devuelve la


posición de la primera ocurrencia.

Mid: búsqueda de una cadena de caracteres en otra cadena de caracteres. El comienzo de la


primera ocurrencia y la longitud de la secuencia a devolver se pasan como parámetros.

LCase: convierte en minúsculas la cadena de caracteres pasada como parámetro.


Left: devuelve los caracteres a la izquierda de la cadena pasada por parámetro. El
número de caracteres se pasa por parámetro.

Len: devuelve la longitud de la cadena pasada por parámetro.

LTrim: elimina los espacios a la izquierda de la cadena de caracteres pasada por


parámetro.

Right: devuelve los caracteres a la derecha de la cadena pasada como parámetro. El


número de caracteres se pasa por parámetro.

RTrim: elimina los espacios a la derecha de la cadena de caracteres pasada por


parámetro.

Space: devuelve una cadena de espacios cuyo número se pasa por parámetro.

String: devuelve una cadena de caracteres. El nombre y los caracteres a devolver se


pasan como parámetros.

Trim: elimina los espacios a izquierda y derecha de la cadena de caracteres pasada por
parámetro.

UCase: convierte en mayúsculas la cadena de caracteres pasada por parámetro.

d. La gestión de fecha y hora

Date: devuelve la fecha de sistema.

DateAdd: suma un periodo a la fecha pasada por parámetro. El periodo a sumar será en
años, trimestres, meses, días, horas, minutos o segundos.

DateDiff: devuelve la diferencia entre las dos fechas proporcionadas. El periodo resultante será
en años, trimestres, meses, días, horas, minutos o segundos.
Day: devuelve el número de día de la fecha pasada por parámetro.

Month: devuelve el mes de fecha pasada por parámetro.

Now: devuelve la fecha y la hora del sistema.

WeekDay: devuelve el día de la semana de fecha pasada por parámetro.

e. Gestión de los mensajes

InputBox es una función que muestra un cuadro de diálogo que permite una entrada de
información con validación por el usuario (clic del botón Aceptar).

Vea la sintaxis y los parámetros obligatorios u opcionales.

InputBox (mensaje, titulo, defecto, xpos, ypos, helpfile, context)

mensaje: zona de mensajes para el usuario.

Titre: título del cuadro de diálogo.

Defecto: cadena de caracteres mostrada por defecto en la zona de entrada del usuario.

Xpos e Ypos: posicionamiento vertical y horizontal en la pantalla del cuadro de diálogo


cuando se abre.

Helpfile: da el nombre del archivo de ayuda contextual. Este argumento obliga a


alimentar Context.

Context: da el número de contexto de la ayuda. Este argumento obliga a alimentar


Helpfile.

Sólo la zona de mensaje no es opcional.

Vea un ejemplo de código y el resultado mostrado en la pantalla.


En todos los cuadros de diálogo se puede insertar un retorno de carro (Chr(13)) o un salto
de línea (Chr(10)) entre las líneas.

Hasta ahora, hemos utilizado el cuadro de diálogo MsgBox para mostrar en pantalla los
resultados de las pruebas. Pero su utilización se ha limitado a su expresión más simple:
un mensaje y un botón Aceptar para cerrarlo. Es posible añadir botones o iconos.

Vea la sintaxis y los parámetros obligatorios u opcionales.

MsgBox (mensaje, tipo, titulo)

Mensaje: zona de mensajes para el usuario.

Título: título del cuadro de diálogo.

Tipo: define el número y el tipo de botones, así como el icono que aparece en el cuadro.
Este número es una suma de código que proceden de 4 grupos: tipos de botones, tipos
de iconos, botón por defecto y modalidad.
El clic de un botón retorna un valor que devuelve la función MsgBox. Este valor es de tipo
Integer.

Vea un ejemplo de código y el resultado mostrado en pantalla.


Organización del código y metodología
Hemos hablado a través de ejemplos anteriores de ciertas reglas de escritura de un
programa. De hecho, hay normas y estándares de desarrollo que hay que respetar. El
hecho de no respetarlas no impedirá quizá que las aplicaciones que cree funcionen, pero
son buenos hábitos de trabajo para ayudar a la legibilidad y al mantenimiento de sus
programas. Vamos a revisar algunos puntos ya abordados previamente.

1. Comentarios y documentación del código


Los comentarios aportados a las secuencias de código de los ejemplos anteriores,
permiten dar explicaciones para ayudar a los programadores principiantes a su
comprensión. En el contexto de un desarrollo real, este tipo de explicaciones detalladas
del código tienen razón de ser, para los párrafos particularmente complejos o poco
utilizados. Los comentarios están destinados a describir las principales funcionalidades
del programa. Cada nuevo bloque de código en un procedimiento debe tener un breve
comentario a modo de introducción que permita a cualquiera hacerse una idea rápida sin
tener que analizarlo todo. Este paso es esencial para cualquiera que pueda intervenir en
el futuro para añadir correcciones o evolutivos. Además, estos comentarios pueden serle
útiles porque no siempre es fácil volver a introducirse en un programa escrito hace
algún tiempo.

En función del tamaño de la aplicación y del alcance de su despliegue a los usuarios,


puede ser oportuno poner a disposición del público la documentación. Esta
documentación se dirige a diferentes tipos de público, por lo que posiblemente hará falta
escribir más de un manual. Su función será describir y explicar el funcionamiento de la
aplicación. Quizá será necesario escribir un manual de usuario y un manual técnico para
los desarrolladores eventuales susceptibles de trabajar en el programa. Se recomienda
no esperar al último momento para empezar a escribir la documentación y hacerlo a
medida que se va avanzando en la escritura del código.

2. La estructura del código


Las declaraciones de variables se reagrupan en el inicio de los procedimientos. Por
supuesto, esto depende de su alcance. Las variables disponibles para todos los
procedimientos se declaran al inicio del módulo. A veces es interesante declarar
variables públicas de ámbito global en un módulo concreto.

No dude en externalizar los bloques de código repetitivos con el fin de evitar


redundancias en el programa. Una vez se almacena la secuencia en un procedimiento
público, basta con hacer una llamada a este procedimiento para ejecutar las
instrucciones esperadas sin tener que reescribirlas en el programa. Así se aligera y se
modula el código. Este proceso permite la exportación y la reutilización de ciertas
secuencias en aplicaciones futuras en las que no es extraño desarrollar funcionalidades
idénticas.

Las líneas de código demasiado largas pueden suponer problemas en función del
tamaño de la pantalla. La lectura de un código puede ser más difícil si hay que
desplazarse por la pantalla. Se puede utilizar el carácter Under Score (_) para saltar a la
línea siguiente sin romper la instrucción en 2.

La sangría hace resaltar en el código algunos bloques que agrupan condiciones y bucles.
Esto es útil en algunos algoritmos en los que condiciones y bucles están anidados unos
en otros en diferentes niveles. La sangría ayuda a resaltar el nivel de anidamiento y la
prioridad de ejecución de las secuencias.

3. La denominación de los objetos y los controles


Igual que para las variables, el nombre dado a los objetos o a los controles del programa
es importante. Este nombre debe identificar el tipo de objeto o de control así como su
razón de ser en la aplicación. Un formulario de acceso a la aplicación llamado por
defecto UserForm1 por VBA se podría llamar FrmIdent. Frm por formulario e Ident por
identificación. De este modo la lectura del código permite mostrar que se trata de un
formulario para que los usuarios se identifiquen. Este regla también es válida para el
nombre de los procedimientos y de los módulos. Un módulo dedicado a la declaración
de variables podría transformarse de Module1 a ModuloDeclaracion (es mejor evitar los
acentos).

Las mayúsculas no están aquí sólo para resaltar las cadenas de caracteres. Dado que el
lenguaje VB distingue las mayúsculas y minúsculas, si escribe un nombre de un objeto
en su código cuidando respetar la ortografía, VB pondrá automáticamente los caracteres
que deban estar en mayúsculas. De este modo usted sabe que el programa ha reconocido
bien su objeto. Esto no ocurre cuando hay una falta de ortografía. En el momento de la
compilación del programa, en el momento de la ejecución, no se reconoce el objeto y el
programa muestra un error. Este tipo de error no es fácil de detectar en el código. Es
peor cuando hay concatenaciones de cadena de caracteres con variables u otros tipos de
objetos.

4. La ergonomía de la interfaz de usuario


La interfaz debe ser estándar e intuitiva. Trate de construir sobre los estándares
existentes de aplicaciones ya desarrolladas en su ámbito de trabajo. Trate también de
inspirarse en soluciones implementadas por las herramientas informáticas más
comúnmente utilizadas. Los usuarios ya están familiarizados con estos productos y
tardarán menos tiempo en aprender a utilizar el suyo.

Trate de evitar la sobrecarga de los formularios u hojas de trabajo con demasiados


controles. Eleva el riesgo de confundir al usuario. Es mejor agrupar estos controles por
temas o clasificarlos para repartirlos en otros formularios u hojas de trabajo.
El potencial de la aplicación se puede ver en la automatización de las tareas a las que da
soporte y en el mínimo de acciones que se piden al usuario. En un clic de botón, debe
realizar multitud de tareas aburridas y costosas en tiempo sin tener que confirmar,
validar o aceptar acciones.

Por último, hay que tratar el aspecto gráfico eligiendo colores, fuentes y una buena
disposición de los controles. Las aplicaciones deben ser fáciles de utilizar para los
usuarios.

5. La gestión de un proyecto
La gestión de un proyecto se divide en 3 fases ineludibles: el análisis, el desarrollo y la
entrega.

Al contrario de lo que imaginan muchos programadores, la parte del desarrollo es de


largo la más corta. El porcentaje de cada una de estas tres fases en un proyecto es la
siguiente: 40% de análisis, 20% de desarrollo y 40% de entrega.

 El análisis define las reglas de gestión de la aplicación. Permite identificar los


diferentes actores involucrados y los diferentes flujos de información entre éstos.
Es necesario efectuar una auditoría con los futuros usuarios con el fin de definir
con ellos sus necesidades. Puede hacer proposiciones de funcionalidades
susceptibles de interesar a los usuarios. Además, es importante en la medida de
lo posible implicar a los futuros usuarios del producto. De este modo, estos
últimos no se sienten finalmente ante hechos consumados y todas las
funcionalidades de la aplicación han sido validadas previamente por las dos
partes. Por último, todos estos intercambios de información se deben consignar
en un cuaderno de carga que servirá de hilo conductor en el desarrollo y
legitimará todas las acciones emprendidas.
 El desarrollo puede comenzar una vez ha terminado la fase análisis. No hay que
olvidar hacer copias de seguridad regulares del código a medida que se avanza
en el trabajo. No dude en hacerlo varias veces al día una vez se ha completado
una fase del desarrollo. Esta recomendación puede parecer superflua pero tras un
uso incorrecto por parte de otro programador, la caída de un ordenador, un error
de red... se puede perder una jornada completa de trabajo. Se deben mantener
versiones con la fecha de avance de la aplicación porque aunque esté seguro de
su análisis, siempre es posible echar marcha atrás a lo largo del desarrollo.
 La entrega se hace cuando se ha completado la fase de desarrollo. A lo largo de
la codificación, se han hecho pruebas unitarias de los diferentes bloques de
código y procedimientos escritos. Pero las pruebas de la aplicación no puede
hacerlas realmente más que una persona externa que sabrá encontrar errores que
no se ven en la fase de desarrollo. Es normal y común a todos los
desarrolladores experimentados o no. Es casi imposible (excepto con un
programa muy pequeño) que el código esté exento de correcciones después de
una primera entrega. A veces hay fallos de diseño que hacen que la aplicación
no responda exactamente a las especificaciones del cuaderno de carga y hay que
hacer correcciones. El usuario también puede decidir que sus necesidades han
cambiado: esto no serán entonces correcciones pero sí evolutivos y el tiempo
suplementario irá a su cargo.
Una vez se completen las tres fases, el programa se pone en producción.

El entorno de desarrollo en Excel


VBA es el soporte a nivel de programación de la mayor parte de las aplicaciones de
Office. Aunque existen instrucciones comunes a todas estas aplicaciones basadas en el
lenguaje VB, hay muchas características y funcionalidades para cada una de las
aplicaciones. Por contra, el editor VBA o IDE (Integrated Development Environment)
es sustancialmente el mismo para todas las aplicaciones. Vamos a ver cómo trabajar en
este entorno. A continuación vamos a recuperar código VBA a partir de macros Excel
para trabajar a través del IDE.

1. La plataforma de desarrollo
Para utilizar el IDE, puede instalarlo a través de la pestaña Programador de su hoja
Excel.

1. Abra con un clic secundario del ratón en la cinta un menú contextual en el que
tiene que escoger el menú Personalizar la Cinta de opciones :

En el cuadro de diálogo Opciones de Excel, seleccione en la lista Fichas principales la casilla


Programador.
En la pestaña Programador, puede ahora hacer clic en el icono Visual Basic.

También es posible utilizar simplemente el atajo de teclado [Alt][F11].

a. La presentación de las ventanas

Vea el IDE tal y como se ve al abrir. Este entorno se compone de diferentes ventanas
que vamos a revisar.
La ventana de proyecto

Esta ventana agrupa los diferentes componentes del proyecto como los objetos del libro,
los UserForm (o formularios), los módulos y los módulos de clases (creación de objetos
personalizados). Estos componentes se organizan en forma de árbol en las carpetas. Es
posible modificar la apariencia de este árbol con el botón . Cada uno de los
componentes contiene código visible en la ventana de código. Basta con seleccionar el
componente y hacer clic en el botón . Esta operación también se puede hacer con un
doble clic en el componente. Si selecciona un Userform, puede visualizar los diferentes
objetos en la ventana de código con el botón .

Con un clic derecho en un proyecto, el menú contextual Insertar permite añadir


componentes como los UserForm, los módulos y los módulos de clases. Del mismo
modo, también es posible importar (Importar un fichero...) uno de estos componentes,
de exportarlo (Exportar un fichero...) o suprimirlo (Quitar Nombre de fichero...).

Haciendo Drag and Drop, se puede copiar un componente de un proyecto abierto en el


IDE a otro proyecto.
La ventana de propiedades

Esta ventana muestra todas las propiedades de los objetos y controles del proyecto.
Según la pestaña elegida, estas propiedades se pueden visualizar clasificadas
alfabéticamente o agrupadas por categorías.

El explorador de objetos
Esta ventana visualiza los diferentes objetos de VBA con sus propiedades, sus métodos
y sus eventos. Una función de búsqueda permite encontrar fácilmente estos objetos,
propiedades, métodos o eventos.

b. La zona de código

La ventana de código es común a todos los componentes del proyecto. En la zona


superior de la ventana se puede acceder a dos listas desplegables. La de la izquierda
muestra los objetos disponibles del componente seleccionado. La lista desplegable de la
derecha muestra los eventos disponibles para el objeto seleccionado en la primera lista.
Si no hay ningún objeto seleccionado, habrá una lista de procedimientos no ligados a
ningún evento.
En esta ventana de código existen numerosas funciones de ayuda a la escritura y de
control del código a escribir.

 Si escribe los primeros caracteres de una palabra y selecciona [Ctrl][Espace] en


el teclado, VBA completará la palabra. Si el número de carácteres introducidos
no es suficiente y hay ambigüidad entre diferentes términos posibles, se le
propondrá una lista desplegable en la que podrá elegir el que desee.

La sintaxis de las funciones, métodos o procedimientos se visualiza en la ventana de código.

Después, introduciendo un punto a continuación del nombre de un objeto, aparece una lista
desplegable que muestra las propiedades, métodos y eventos asociados a este objeto.
Esta funcionalidad es una gran utilidad y de muy fácil uso. Permite a los
programadores encontrar la propiedad, el método o el evento que se ajuste a las
necesidades del programa. Como último recurso le queda, naturalmente, el explorador
de objetos.

 Después de haber introducido la propiedad de un objeto, VBA puede mostrar a


la derecha del signo = las constantes predefinidas posibles.

 En modo depuración o Break, si el cursor está sobre una variable, VBA muestra su
contenido.

Los siguientes botones están en la barra de menú Edición y en el menú del IDE Ver - Barras de
herramientas - Edición.
c. La ejecución del código

Para ejecutar el código a partir de la ventana de código, basta con situar el cursor en un
bloque de código ejecutable. Por ejemplo en el caso de un procedimiento que no tiene
espera parámetros.

A continuación se puede utilizar la tecla [F8] para hacer avanzar el código paso a paso.
Este método tiene todo su interés en el ámbito de un proceso de depuración. [Ctrl][F8]
ejecutará el código hasta el cursor.

Con un clic izquierdo del ratón en el margen del programa, se puede insertar un punto
de interrupción. Esto suspende la ejecución del código al nivel de la instrucción donde
se ha colocado.

La tecla [F5] lanza la ejecución hasta el fin de la secuencia del programa.

d. La caja de herramientas

Muestra el cuadro de herramientas.


Haciendo Drag and Drop, se puede desplazar los controles disponibles en el cuadro de
herramientas a un formulario o UserForm.

Posteriormente se detallarán las diferentes herramientas de este cuadro.

2. Las macros y el código VBA


El grabador de macros permite grabar multitud de operaciones realizadas para obtener
un resultado. Una vez se ha grabado la marco, una simple llamada a la macro permite
repetir esta operación. Pero el interés reside también en el hecho de que se puede
recuperar el código VBA asociado a las diferentes acciones grabadas. Se puede acceder
a todas las macros grabadas por el programador en el IDE, siendo cada una de ellas un
procedimiento grabado en un módulo.

Pero existen límites a este proceso. De hecho, la macro graba todas las acciones del
usuario incluidas las equivocaciones y correcciones. Ocurre igual con los clics de
validación o de selección y los desplazamientos con los cursores. Por el contrario, no se
graban las instrucciones entradas con el ratón. Tanto para un clic izquierdo como para
uno derecho (menus contextuales).

Por último, el código generado no siempre es óptimo y adolece de algunos defectos.

El siguiente ejemplo lo muestra.

 Ejecute la grabadora de macros. Por defecto, esta macro se llamará en nuestro


ejemplo Macro1. La macro se graba en Este Libro para mostrarse en los
módulos de su libro activo. Haga clic en el botón Aceptar para validar el inicio
de la grabación.
 Grabe la siguiente operación en una macro. Seleccione la celda A1 en la que escribirá 1
Hora. Haciendo clic en la esquina inferior derecha de la celda, estire hasta 24 celdas,
hasta la celda X1. Se incrementa el número y se obtiene esto:

 Su pantalla no es suficientemente grande. Para volver a la columna A, debe usar la


barra de desplazamiento horizontal. Seleccione de nuevo la celda A1. Ahora puede
parar el grabador de macros.

Si abre el IDE, encontrará la Macro1 en forma de un procedimiento en un módulo llamado


Modulo1 por defecto por VBA.
El código generado por el grabador de macros es el siguiente:

Es posible llenar directamente la celda A1 sin tener que seleccionarla previamente con
el código Range("A1").Value = "1 hora".

La línea de código Selection.AutoFill Destination:=Range("A1:X1"),


Type:=xlFillDefault llena e incrementa en las 23 celdas siguientes, la cadena de
caracteres 1 hora. Es una instrucción específica de VBA aplicado a Excel. Es difícil
conocerla y el grabador de macros revela toda su utilidad.

Toda la zona ActiveWindow.ScrollColumn representa el desplazamiento de la barra de


desplazamiento en el libro activo y no es útil.

Vea ahora una versión optimizada del código.

Se obtiene un resultado idéntico sólo con dos líneas de código. Por tanto es útil hacer un
poco de limpieza en el código recuperado de una macro.
Añadamos ahora una acción suplementaria. Usted quiere que se seleccione la última
celda de la linea (Celda X1). En lugar de utilizar la barra de desplazamiento horizontal
en la grabación de su macro para desplazarse, utilice el atajo de teclado [Ctrl][Cursor
derecho] que selecciona directamente la última celda de la línea.

La instrucción se traduce en una sola instrucción, sea cual sea la longitud de la línea.

3. Para mostrar la ayuda


Existe a disposición del programador la documentación en formato electrónico. El menú
del IDE ? - Ayuda de Microsoft Visual Basic abre una ventana de ayuda.

La tecla [F1] permite acceder a esta misma ayuda si el cursor está situado en una instrucción
del código, una ventana del IDE o un control de un formulario. Si por ejemplo se selecciona
una instrucción Sub, la ventana de ayuda se abre en la definición correspondiente.
Internet es otra fuente de información. Basta con teclear directamente una pregunta en un
motor de búsqueda para que aparezca una lista de sitios y foros de discusión que tratan
problemas de código VBA, todo en entornos de habla española.

Primeras manipulaciones y gestión de candidatos


Objetivos
A través de este proyecto de gestión de personal para una agencia de colocación
profesional, va a aprender a gestionar los libros y las hojas y su contenido. Necesitará
los ficheros Agencia_trabajo_temporal.xls y Modelo_Equipo.xls que se pueden
descargar de la web de la editorial.

Veremos como recuperar y adaptar a nuestras necesidades la diferentes funcionalidades


de Excel para gestionar los datos. Para esto, utilizaremos el grabador de macros (véase
el capítulo Excel y la programación - sección El entorno de desarrollo en Excel) para
recuperar de ellas el código VBA. El código recuperado se estructurará y organizará con
el lenguaje VB a través de módulos y procedimientos.

Lo eventos podrán invocar a los procedimientos con la posibilidad de pasar parámetros.

A continuación, será necesario probar y depurar estos procedimientos con las


herramientas de depuración.

Además, se grabarán los trabajos realizados tanto a nivel de hojas del libro como a nivel
de la plataforma de desarrollo.
El capítulo termina con operaciones de directorios en VBA.

En primer lugar, le será necesario crear un directorio de trabajo en la raíz de su disco


duro. Le llamará Formacion VBA Excel 2010. En este directorio se almacenarán todos
los archivos relacionados con esta formación como los ficheros de descarga
(Agencia_trabajo_temporal.xls, Modelo_Equipo.xls...) o los producidos durante los
ejercicios. Una vez haya creado el directorio, puede guardar los ficheros descargados.

a gestión de los libros y las hojas


En esta sección, la lista de personas inscritas en la agencia de trabajo temporal así como
su profesión se cargará en un libro de trabajo. Esta lista está almacenada en el libro
Agencia_trabajo_temporal.xls que se debe abrir y volver a cerrar después de haber
copiado los datos. Veremos enseguida como gestionar las hojas del libro de trabajo:

 Hoja de trabajo
 Hoja de referencia del proyecto
 Plantillas

Los utilizaremos en modo de creación, eliminación o importación.

1. Apertura del libro de inscritos


1. Abra un nuevo libro y el IDE ([Alt][F11]).
2. Grabe el libro llamándolo "Gestion de Perfiles".

Es interesante coger el hábito de tener las dos ventanas abiertas al mismo tiempo. Así es
posible acceder rápidamente al código o a las hojas del libro de trabajo. Además durante
las pruebas de las macros, es posible ver el resultado del despliegue del código (modo
depuración con la tecla [F8]) a nivel de las hojas del libro. Naturalmente, cuanto más
grande sea su pantalla, más interesante será este método.
 Inserte un módulo en el proyecto. Utilice el menú Insertar - Módulo o busque
esta funcionalidad en el menú contextual haciendo clic con el botón secundario
del ratón en el explorador del proyecto.

Ahora debe insertar en este nuevo módulo (Modulo1 por defecto, según el orden de
creación) un procedimiento que debe llamar AperturaLibro.

 Utilice el menú de inserción del IDE, Insertar - Procedimiento y rellene el


formulario como en la figura.

Sub define un procedimiento y Public lo hace accesible al resto del proyecto.

 Escriba el siguiente código en el procedimiento:


El resultado en el IDE debe ser el siguiente:

Debe acostumbrarse rápidamente a escribir el código directamente en el IDE en


lugar de pasar por el menú anterior. Esta es la manera de añadir comentarios.

La línea de comentario comienza siempre con una comilla simple incluso cuando
hay un salto de línea.

Todas las cadenas de caracteres alfanuméricas en el código se escriben con dobles


comillas (".....") al inicio y al final de la cadena.

El término ChDir permite apuntar al directorio en el que se encuentra el libro que desea
abrir.

Después del comando Workbooks.Open Filename:= se colocan la ruta completa y el


nombre del libro.

En estas dos líneas de código, se pueden utilizar variables para que el procedimiento
pueda abrir diferentes libros modificando la ruta de acceso y el nombre del documento.

 Modifique el código del siguiente modo.


La ruta del directorio y el nombre del fichero se concatenan: StrRuta & StrNomFic (lo
que equivale a escribir "C:\Formacion VBA Excel 2010\
Agencia_trabajo_temporal.xls").

Las dos variables se alimentan por código pero es posible utilizar el paso por
parámetros. Este concepto se verá con más detalle en este capítulo un poco más tarde.

Recuerde, Option Explicit obliga a la declaración de variables. Esto no es obligatorio


pero es altamente recomendable para la integridad del código.

Sólo hay que ejecutar el procedimiento para ver el resultado.

 Sitúe el cursor en el procedimiento y haga clic en el botón Ejecutar de la barra


de herramientas del IDE ( ) o pulse la tecla [F5] del teclado.

El libro Agencia_trabajo_temporal.xls se abre en primer plano. Se puede ver la lista de


inscritos de la empresa de trabajo temporal con su apellido, nombre, profesión y
disponibilidad.

2. Recuperación de la lista de inscritos


Tenemos la necesidad de cargar los datos contenidos en el libro
Agencia_trabajo_temporal.xls. Estos datos están en la hoja Lista de inscritos.

Hay que posicionarse en la hoja correcta del libro, seleccionar los datos, copiarlos para a
continuación volver al nuevo libro y pegar los datos en una hoja de trabajo.

Vea el código a añadir después de la apertura del libro.


Sheets(<nombre>) hace referencia a través del parámetro nombre a una hoja del libro
activo. La propiedad Select permite seleccionar una hoja. Para un libro abierto
Windows(<nombre>), se utilizará la propiedad Activate. La instrucción Cells.Select
selecciona todo el contenido de una hoja antes de copiarla. Range(<dirección>)
corresponde a una celda de la hoja activa del libro. La dirección se expresa en forma de
una letra que hace referencia a la columna y un número que corresponde a un número de
fila. Range("A1").Select posiciona la celda A1 antes de pegar los datos. ActiveSheet
devuelve a la hoja seleccionada (activa) del libro activo por defecto.

El objeto Range se puede sustituir por Cells(<dirección>). La dirección se expresa


en forma de dos números. El primero corresponde al número de fila y el segundo al
número de columna. Esta forma es interesante en el caso de que haya que enumerar e
incrementar el número de columna. Esto no es posible con las letras del alfabeto.

Una hoja del libro se llama por su nombre pero también por un número de índice
directamente vinculado a su orden de creación. De este modo la instrucción
Sheets("Lista de inscritos").Select es equivalente a la instrucción Sheets(1).Select.

3. Cierre del libro


Una vez se han copiado los datos, hay que cerrar el libro origen. Debe reactivar éste
último para cerrarlo a continuación.

 Añada este código en el programa.

El libro activo se cierra con Close.

Si hubiera modificaciones en el libro Agencia_trabajo_temporal.xls, aparecerá un


mensaje que nos pide la confirmación de la grabación de las modificaciones. Para evitar
este mensaje que molesta a la automatización de la aplicación pidiendo confirmación al
usuario, basta con añadir la instrucción SaveChanges:=False para ignorar las
modificaciones o SaveChanges:=True para grabarlas. Debe situarlo después de Close.
La confirmación se hace directamente a nivel de código y el mensaje no se visualiza.

4. Gestión de las hojas de trabajo


Después de haber copiado los datos, puede renombrar su hoja y eliminar las dos hojas
siguientes que son inútiles.

La instrucción Array crea una tabla que permite seleccionar las dos hojas a la vez.
SelectedSheets hace referencia a las hojas seleccionadas para suprimirlas con Delete.

La hoja de trabajo es una hoja con la que podrá hacer diversas operaciones como
almacenar datos, efectuar cálculos o ajustes. Es provisional y se crea durante la
ejecución del programa. Piense también en eliminar las hojas inservibles como las
insertadas por defecto cuando se crea un libro (ver las opciones definidas por defecto).
Esta operación permite aligerar al máximo sus libros para el almacenamiento o su envío
a terceros.

Proceda ahora a la prueba de estas nuevas funcionalidades insertadas en el código. Para


hacerlo, debe seleccionar la parte relativa a la apertura del libro
Agencia_trabajo_temporal.xls. Comente todo este bloque de código con el botón
Bloque con comentarios de la barra de herramientas Edición del IDE.

Para volver a poner el código activo, basta con utilizar el botón Bloque sin comentarios
.

 Seleccione el código que va de la línea 6 a la 17 inclusive. Coméntelo.

Como muestra la siguiente imagen, un elemento de la barra de herramientas del


IDE le indica la posición del cursor. Li 6, Col 5 corresponde a la posición de
inicio de la selección del bloque a comentar:

Vea el resultado obtenido en el IDE:


Todas las línea del bloque de código seleccionado ahora tienen simpre una comilla
delante.

 Ahora puede ejecutar el proceso.

Todo ha funcionado según lo previsto excepto un mensaje que le pide que confirme la
eliminación de las hojas.

Seguro que habrá confirmado esta eliminación.

Pero en términos de automatización de tareas, es absurdo pedir al usuario que confirme


operaciones de un programa que se supone que se ejecuta automáticamente. Existe un
código que en estos casos permite evitar este tipo de mensajes.
 Complete el código suprimiento las dos hojas a través de dos líneas de código
del siguiente modo.

Si desactiva los avisos de Excel en el inicio de un bloque de código, no olvide


volverlos a activar al final del bloque ya que puede necesitarlas más tarde en su
programa.

Los mensajes que proceden del sistema operativo no están afectados por este código
y siguen estando activos.

5. Creación de una hoja de referencia de la


herramienta
La hoja de referencia es diferente de una hoja de trabajo. Contiene información
indispensable para la ejecución del código. Estos datos generalmente son invariable y
permanentes. Esta hoja, en general, se oculta, ya que su contenido no tiene interés para
el usuario y puede ser confidencial.

 Añada este código en el programa.

En primer lugar, Sheets.Add inserta una nueva hoja. Se sitúa por defecto delante de la
hoja activa. Aunque esta hoja se va a ocultar, es preferible situarla al final del libro.
Partiendo de la base de que es posible encontrar una hoja tanto por su nombre como por
su número de índice, es posible identificarla como la última de un conjunto de hojas. De
este modo, after:=Sheets(Sheets.Count) permite situarla después de la última hoja del
libro en el momento de su creación. La propiedad Count cuenta el número de hojas del
libro. Podemos descontar dos hojas en el libro. La nueva hoja se insertará después de la
segunda.

La hoja se llama Hoja1, 2 o 3 en función del orden de creación. ActiveSheet.Name =


"Referencias" la personaliza cambiando su nombre para que el programa la pueda
encontrar.

Sheets("Referencias").Visible = False oculta la hoja.


1. Pruebe el código comentando todo lo anterior. Parece que no ha pasado nada
pero si va a ver las hojas ocultas del libro, la hoja "Referencias" existe (Pestaña
Inicio - Formato - Ocultar y mostrar - Mostrar hoja).

Esta hoja la dejaremos de lado por el momento, se utilizará en el proyecto más tarde.

6. Creación de una plantilla de lista de equipo


disponible
La plantilla constituye un documento guardado en un directorio para utilizar el
contenido como se quiera. Como es el caso de los Templates de las herramientas de
Office.

En el ámbito de la herramienta de gestión de candidatos, vamos a utilizar una primera


plantilla destinada a la creación de una lista de individuos disponibles y que respondan a
la petición de un cliente. Estos perfiles se organizarán antes de repartirlos en un
calendario.

En el ámbito de un contexto multi usuario, las plantillas necesarias para el funcionamiento


de su aplicación tienen que estar accesibles para todos los usuarios y por ello se almacenan en
la red (al contrario de los Templates que se guardan en los ordenadores de los usuarios).

 Cree un nuevo directorio llamado Plantillas para guardar el archivo


Plantilla_Equipo.xls del que se muestra la primera pestaña en la imagen de
abajo. También puede guardar el libro Agencia_trabajo_temporal.xls.

Sería una perdida de tiempo automatizar con VBA el diseño de esta máscara de
entrada, ya que el hecho de que esté guardada en un directorio la preserva de cualquier
modificación voluntaria o involuntaria por parte del usuario.
 Inserte en el módulo un nuevo procedimiento llamado AperturaPlantillas. Inserte
a continuación el siguiente código:

Respecto a la apertura del libro, el código es idéntico al del primer procedimiento. Así que en
lugar de declarar de nuevo las variables StrRuta y StrNomFic, es más sensato modificar su
ámbito. Basta con desplazar estas declaraciones a la parte superior del módulo, justo debajo
de la instrucción Option Explicit.

Estas dos variables están ahora disponibles para todo el módulo. No es necesario
declararlas al inicio del procedimiento, sólo hay que alimentarlas.

El código Sheets("Profils").Copy Before:=Workbooks("Gestion de


Perfiles.xls").Sheets(2) inserta una copia de la hoja Perfiles de Plantilla_Equipo.xls en
el libro Gestion de Perfiles.xls.
La plantilla se cierra al final del procedimiento.

 Pruebe el procedimiento AperturaPlantillas().

El libro tiene ahora tres hojas:

 Lista de inscritos
 Perfiles
 Referencias (Hoja oculta)

Llamada de procedimientos en la herramienta y gestión del


código
Ahora hay que reorganizar el código a través nuevos procedimientos. Para hacerlo, hay
que trasladar partes de código redundante y gestionar variables globales en un módulo
único, disponible para toda la aplicación. A continuación veremos cómo trabajar con
llamadas a procedimientos.

1. Creación del módulo de declaraciones


1. Inserte un nuevo módulo y renómbrelo como ModDeclaracion.

Para cambiar el nombre por defecto que da VBA, hay que ir a la ventana de
propiedades. Si selecciona el nuevo módulo en la ventana de proyecto, aparecen sus
propiedades en la ventana de propiedades.
A continuación tiene la posibilidad de abrir la lista desplegable en la parte superior
de la ventana de propiedades son están todos los objetos disponibles del módulo, del
formulario o de la hoja seleccionada.

En este caso, sólo hay una propiedad disponible para el nuevo módulo. Se trata de la
propiedad Name. Asígnele el nombre ModDeclaracion en lugar del nombre por defecto.
Mod como prefijo que identifica un módulo y Declaracion como el lugar donde se
guardarán las variables globales del programa.

Desplace las variables StrRuta y StrNomFic a este módulo.

Las variables se declaran como Public y así son accesibles por todos los módulos y
todos los procedimientos de la aplicación. El módulo de declaración crecerá a medida
que avance el desarrollo. Entonces será necesario agrupar las variables por temas y
añadir un breve comentario descriptivo. Todo esto se hace para facilitar la comprensión
del código en el futuro.

2. Optimización del código para la gestión de perfiles


El código que hemos visto hasta ahora se puede optimizar.

1. Renombre el primer módulo como ModGestionLibro. A partir de ahora


agruparemos aquí todas las instrucciones que traten sobre la gestión de libros.
2. Renombre el procedimiento AperturaLibro por CargaPerfiles. Modifique al
mismo tiempo el comentario ’Apertura de un libro de la línea de debajo y
escriba ’Carga de perfiles.
3. Suprima los bloques de instrucciones de cambio de nombre, de eliminación de
hojas y de inserción de la hoja de referencia (de la línea 30 a la línea 47
incluida). Estas operaciones no estarán en la aplicación.

3. Procedimientos sin parámetros


Los dos procedimientos que hay en ModGestionLibro presentan una redundancia. Se
trata de las líneas de instrucciones que permiten abrir un libro. En estos procedimientos,
el código es idéntico. Con el fin de evitar esta repetición, hay que trasladar este trozo de
código a otro procedimiento.

1. Inserte un nuevo procedimiento y llámelo AperturaLibro. Puede copiar el bloque


de código y sustituirlo en los procedimientos de origen por una llamada de
procedimiento: Call AperturaLibro.
AperturaLibro es un procedimiento sin paso de parámetros ya que estos últimos se
alimentan en el código a través de dos variables globales.

Esta alimentación por código sólo es provisional y lo corregiremos más tarde. Este
proceder se debe evitar en la medida de lo posible. En el estudio de este ejemplo,
significará que la ruta de acceso a los ficheros es inamovible. Esto es un absurdo y
elimina cualquier flexibilidad a la aplicación en su interacción con el entorno.

 Pruebe los procedimientos CargaPerfiles y AperturaPlantillas. Pero primero,


borre el contenido de la hoja Lista de inscritos y suprima la hoja Gestion de
Perfiles. Todavía hay que hacer otra operación si quiere evitar el siguiente
mensaje:

 Debe neutralizar este mensaje con la propiedad DisplayAlerts en el momento del


cierre del libro Agencia_trabajo_temporal.xls.

El libro vuelve a tener tres hojas y vea el código del módulo ModGestionLibro actualizado:
4. Procedimientos con parámetros
Vamos a llevar a cabo una nueva funcionalidad que permitirá al usuario extraer una lista
de candidatos según el perfil buscado.
a. Concepción de la interfaz

Comencemos por transformar en interfaz de usuario la hoja Gestion de Perfiles. De


hecho, vamos a insertar un control de tipo Botón de comando.

 A partir del menú Insertar y de la caja de herramientas Controles ActiveX de la


barra de herramientas Programador, haga clic en Botón de comando (Controle
ActiveX) y dibújelo sobre la hoja de trabajo. Haga clic en el menú Modo Diseño
para inutilizar la hoja.

 Seleccione el control CommandButton1 haciendo clic con el botón secundario del


ratón y haga clic en Propiedades del menú contextual.
Todos los controles de la lista dependen de la hoja Lista de inscritos. Puede renombrar
su control en el programa introduciendo:

 CmdListaPerfiles en la propiedad Name


 Lista de perfiles en la propiedad Caption

b. Codificación de la funcionalidad

 Cierre la ventana de propiedades y haga clic el botón secundario del ratón en el


menú contextual, para visualizar el código asociado al botón de comando en la
ventana de código.
El IDE muestra un procedimiento que depende del botón de comando y está asociado
por defecto al evento Click. Éste es el evento a partir del cual hay que codificar la
funcionalidad ya que es un clic del usuario el que va a ejecutar esta parte del programa.

También la hoja Gestion de Perfiles que depende del botón CmdListaPerfiles se verá
afectada por el código que escribiremos.

Cada control tiene un evento por defecto.

 Inserte ahora el siguiente código que va a implementar la selección de una


habilidad en el procedimiento CmdListaPerfiles_Click.

En primer lugar, se vacía el contenido de la celda destino. De este modo, si al final el usuario
no escribe nada, el posible contenido anterior que hubiera en Range("F5").value no se tendrá
en cuenta. El objeto InputBox recupera la habilidad introducida por el usuario y la carga en la
celda de destino.
Si el usuario no introduce ninguna habilidad, el procedimiento se interrumpe con la
instrucción Exit Sub.

 Cree ahora un procedimiento general que extraiga los candidatos cuyo perfil
corresponda a la habilidad introducida por el usuario. Llámelo
CargaListaPerfiles.

Para efectuar esta extracción, el procedimiento debe recuperar la habilidad que se le va


a pasar por parámetro a través de la llamada al procedimiento con la instrucción Call
CargaListaPerfiles(Range("F5").Value). Esta llamada debe situarse justo después del
control de la entrada de usuario en el procedimiento CmdListaPerfiles_Click.

 Inserte el código siguiente en CargaListaPerfiles.

Con StrHabilidad, la habilidad se transmite al filtro (Selection.AutoFilter) aplicado a la


lista de inscritos (Criteria1) y aplicado en la tercera columna (Field:=3).

Puede recuperar el código de creación de un filtro con el grabador de macros. A


continuación basta con adaptar el procedimiento según las necesidades.
Una vez se ha filtrado la lista, los datos restantes se copian en la hoja Gestion de
Perfiles. Hay que volver a Lista de inscritos para eliminar el filtro. Por último, el
procedimiento se posiciona otra vez en Gestion de Perfiles.

 Puede probar el código.

Como puede comprobar, toda esta serie de idas y venidas entre las dos hojas es visible
en la pantalla durante la ejecución del código. Esto no es lo mejor. Puede remediarlo
congelando la pantalla de código. Basta con utilizar la instrucción
Application.ScreenUpdating a True para congelar la pantalla y a False para
descongelarla.

 Inserte esta instrucción a True justo antes de la llamada Call


CargaListaPerfiles(Range("F5").Value) y otra vez a False justo después. Pruebe
el código.
Ahora el usuario no aprecia las idas y venidas entre las dos hojas de los libros. La
gestión de este tipo de problemas distingue el desarrollo de un principante de una
aplicación profesional.

Igual que para los mensajes de aviso de Excel, no olvide desactivar el congelado de
la pantalla.

VBA y la gestión de datos cargados


Esta sección detallará la presentación de los datos, tanto la forma como el contenido..

1. Formato de listas
Nuestra lista se va a presentar en forma de una tabla con una cuadrícula de celdas. Esta
cuadrícula se tiene que adaptar a la longitud de la lista y redimensionarse en cada
petición del usuario. Esto es la base de un código dinámico.

El grabador de macros permite recuperar el código de inserción de una cuadrícula.

 Grabe la secuencia de operaciones que le permita obtener el siguiente resultado.

 A continuación, seleccione el rango de celdas a enmarcar, insertar los bordes


finos para cada celda y enmarcar el conjunto con una línea gruesa.

El grabador de macros genera en el IDE un nuevo módulo. La macro generada tiene un


gran número de bloques de código para controlar la secuencia de algunas operaciones:

 Selección del rango de celdas.


 Inserción de bordes simples en las celdas internas.
 Inserción del borde grueso del rango de celdas.
Vamos a optimizar este código explicando el funcionamiento de las instrucciones que lo
componen.

 Renombre el nuevo módulo como ModFormato y la macro como Sub


CuadriculaRango(). En este módulo guardaremos todos los procedimientos
relativos al formato. Serán reutilizables en otros lugares de la aplicación.

a. Selección de la lista de candidatos que responden al criterio

La macro comienza por un rango de celdas definidas por código en el programa. Para
que el código sea dinámico, este rango debe adaptarse a las dimensiones de la lista y
ésta a cada petición del usuario. Hay que crear un bloque de código que recupere la
dirección de la última celda de la segunda columna. Conociendo la de la celda de inicio
([F5]), es posible entonces definir el rango y pasar sus coordenadas por parámetro al
procedimiento Sub CuadriculaRango().

 Inserte el siguiente código al final de CmdListaPerfiles_Click justo después de


la instrucción de descongelación de la pantalla Application.ScreenUpdating =
True.

ActiveCell.Address envía la dirección de la celda activa y en este caso la última de la


lista. Los demás parámetros enviados se explicarán en el siguiente párrafo.

 Modifique el procedimiento e inserte el siguiente código.

StrRangoSeleccionado transmite a la propiedad Range las coordenadas del rango en


formato alfanumérico ("B6:C10" en nuestro ejemplo).

b. Configuración de la cuadrícula

 Inserte este código a continuación del rango seleccionado.


Este código es la versión optimizada de la macro creada por el grabador. Se podrá reducir
todavía más como veremos un poco más tarde. Vea algunas explicaciones de las siguientes
instrucciones:

Este código ser refiere al rango seleccionado y el objeto With permite no tener que
repetir cada vez Selection.Borders(xlEdgeTop). Una vez se han escrito todas las
instrucciones, se cierra con la sentencia End With.

Estas secuencias With - End With se repiten seis veces. Las cuatro primeras representan
los bordes externos del rango. (Superior, inferior, lado izquierdo y lado derecho). Las
dos últimas son la cuadrícula interna (vertical y horizontal). De este modo, xlEdgeTop
define por ejemplo el borde superior.

Cada secuencia tiene tres propiedades: LineStyle define el tipo de línea, Weight su
grosor y ColorIndex su color. En el ámbito de nuestra aplicación, sólo nos interesa el
grosor de la línea. Las otras dos propiedades no cambian. Estos son los parámetros
enviados en la llamada del procedimiento Call CuadridulaRango("B6:" &
ActiveCell.Address, xlMedium, xlMedium, xlMedium, xlMedium, xlThin, xlThin,
xlContinuous, xlAutomatic) que alimentan las tres propiedades.
xlThin envía una línea fina para la cuadrícula interna y xlMedium una línea gruesa para
los bordes externos.

Los parámetros que se envían se recuperan en las siguientes variables declaradas como
Integer ya que xlThin, xlMedium, xlContinuous y xlAutomatic se interpretan en forma
de valores numéricos.

Estas variables son ocho: Superior As Integer, Inferior As Integer, Izquierda As Integer,
Derecha As Integer, Vertical As Integer, Horizontal As Integer, EstiloLinea As Integer
y Color As Integer. Hay seis variables para cada una de las seis secuencias With - End
With. Las dos últimas corresponden a las propiedades LineStyle y ColorIndex que no
cambian en todas las secuencias.

El procedimiento CuadriculaRango ahora es operativo. Pero hay que insertar


funcionalidades suplementarias en el procedimiento CmdListaPerfiles_Click.

Hay que vaciar la lista antes de recargarla y suprimir la cuadrícula que la acompaña.

 Reemplace el trozo de código actual...

... por el siguiente código:

Se verifica la existencia de la lista antes de vaciarla y de suprimir la cuadrícula. A


continuación, se definen las dimensiones del rango para suprimir primero la cuadrícula
y después borrar el contenido de las celdas (Selection.ClearContents).

Las secuencias With - End With se reemplazan por una sola línea de código:
Selection.Borders(xlEdgeLeft).LineStyle = xlNone. Especifica a la propiedad LineStyle
que no hay ninguna línea visible.
Si para el código de creación de la cuadrícula hubiéramos optado por incluir solo la
propiedad Weight, el procedimiento CuadriculaRango hubiera sido el siguiente:

Antes de crear la cuadrícula, hay que comprobar que el filtro de la lista de perfiles
devuelve los candidatos correctamente. En caso contrario creará una cuadrícula que irá
de la celda de inicio ("B6") hasta los límites de la hoja ("IV:65536").

 Inserte el siguiente código de nuevo justo después de la instrucción de


descongelación de la pantalla Application.ScreenUpdating = True.

Un mensaje advierte al usuario de que no se ha encontrado ningún candidato para este


tipo de habilidades.

Vea el código finalizado del procedimiento CmdListaPerfiles_Click.


Ahora puede probarlo.

No olvide utilizar el grabador de macros para recuperar el máximo código y estudiar


su sintaxis. A continuación puede adaptarlo a las necesidades de cada aplicación y
optimizarlo, ayudándose por los ejemplos de código proporcionados en este libro.
2. La clasificación de perfiles y la utilización de
funciones de Excel con VBA
Para hacer que la lista sea lo más funcional posible para el usuario, vamos a hacer la
selección. El programa la gestionará por defecto o la definirá el usuario a su elección.
Para llevar esto a cabo, utilizaremos funciones integradas de Excel con el código VBA.

a. Concatenación del apellido y el nombre

Para recuperar los niveles respectivos de los candidatos de la hoja Lista de inscritos,
vamos a utilizar la función integrada de Excel CONSULTAV (consulta vertical en una
lista). Esta consulta se puede hacer por el apellido de los individuos pero no es
suficiente ya que siempre existe la posibilidad de que haya dos nombres iguales. Para
limitar este riesgo, hay que añadir el nombre. Empezaremos por insertar una nueva
columna al inicio de la hoja en la que vamos a concatenar el apellido y el nombre de
cada candidato.

Para recuperar una función integrada con el grabador de macros, simplemente escríbala
en la barra de fórmulas de su libro con el grabador funcionando. A continuación valide
la fórmula con el botón Introducir de la barra de fórmulas.

Si cierra el grabador y mira la nueva macro generada, encontrará una traducción VBA
de esta función.

 Cree un procedimiento InsercionNivel en la Hoja3 (Gestion de perfiles) e inserte


el siguiente código:
Después de haber insertado una nueva columna, Sheets("Lista de
inscritos").Columns("A").Insert Shift:=xlToRight, es posible concatenar el apellido y el
nombre a partir de la columna B y C.

La fórmula introducida en la celda A2, Sheets("Lista de


inscritos").Range("A2").FormulaR1C1 = "=RC[1] & "" "" & RC[2]" corresponde a la
fórmula =B2 & " " & C2 en la barra de fórmulas del libro.

R define la fila (Row) y C la columna (Column). RC[1] equivale a la misma fila que la
celda destino pero una columna después para B2. RC[2] equivale a la misma fila pero
dos columnas después para C2. A continuación basta con estirar la fórmula hasta el fin
de la lista con la propiedad Autofill habiendo previamente seleccionado la última celda
de la lista. ActiveCell.Row recupera el número de la fila de la celda seleccionada.

b. Recuperación del nivel del candidato

Ahora vamos a insertar una nueva columna en la hoja Gestion de perfiles e insertar la
fórmula CONSULTAV para devolver el nivel correspondiente de cada candidato que
tenga la habilidad esperada por el usuario.

El resultado esperado es este:

 Inserte el siguiente código en el procedimiento InsercionNivel.


La variable IntLgLista permite recuperar la longitud de la lista. Puesto que ésta es
variable en el tiempo, no hay que introducirla a través del código. Además la instrucción
ActiveCell.row nos lleva a la celda activa de la hoja activa. No es forzosamente la
misma una vez que la hoja ha cambiado.

Se inserta una nueva columna y a través de un pegado especial, se copia el formato del
encabezamiento de la columna C en la nueva columna. A continuación, basta con
insertar la fórmula y estirarla hasta el fin de la lista. El código insertado en la celda D6,
FormulaR1C1 = "=VLOOKUP(RC[-2] & "" "" & RC[-1],’Lista de inscritos’!R1C1:R"
& ActiveCell.Row & "C5,5,FALSE)", corresponde a =CONSULTAV(B6 & " " &
C6;’Lista de inscritos’!$A$1:$E$83;5;FALSO) en la barra de fórmulas del libro.
Observe que el valor que alimenta FormulaR1C1 es una cadena de caracteres. Además,
para pasarle el número de línea de la última celda de la lista devuelta por IntLgLista,
hay que concatenar esta variable para que el programa la reconozca como tal y no como
parte de la cadena de caracteres.
Con un nuevo pegado especial, se copian los valores devueltos por la fórmula para
guardar sólo en las celdas éstos últimos. Deshacerse de la fórmula (CONSULTAV)
permite no depender de la columna de concatenación de la hoja Lista de inscritos y a la
vez poder suprimirla sin perder los niveles de los candidatos ya que la fórmula ha
quedado obsoleta.

Terminamos con la cuadrícula de nuestra nueva tabla, lo que permite comprobar que el
procedimiento CuadriculaRango funciona perfectamente.

Ahora sólo queda llevar algunas instrucciones al procedimiento CmdListaPerfiles_Click


para que se integre en el programa la recuperación de los niveles de los candidatos.

 Debe situar la llamada al procedimiento justo después de la gestión de la


cuadrícula.

De nuevo, se congela la pantalla durante el tiempo que se ejecuta el procedimiento


llamado.

 En el inicio del procedimiento debe eliminar los niveles y la cuadrícula y vaciar


la lista.

Para esto basta con eliminar la columna D.

Para poner a blancos la celda que indica la habilidad requerida por el usuario, hay que
tener en cuenta el hecho de que la inserción de una columna desplaza la dirección de las
celdas de columnas siguientes.

 Sustituya la instrucción Range("F5").Value = "" por el código siguiente:


 Pruebe el código.

c. Gestión de la Clasificación

Ahora debemos insertar dos nuevos controles de tipo Botón de opción (llamado también
botón radio) para la gestión de la clasificación.

La particularidad de estos botones consiste en el hecho de que tan sólo es posible


escoger una de las opciones propuestas.

Vea el resultado esperado en la pantalla:

 Active el modo diseño en la barra Visual Basic del libro.

Si se selecciona el control, aparecen unos tiradores que permiten estirar el control en


todas direcciones.
Puede acceder al menú contextual (haga clic con el botón secundario del ratón en el
control) cuando el cursor toma la apariencia de una cruz cuando pasa sobre el control.

 En el menú contextual, escoja Formato de control.

En la pestaña Propiedades, escoja la opción Mover, pero no cambiar tamaño con celdas
que permite la inserción de la columna de los niveles desplazando los controles sin que
se vea afectado su tamaño. Efectúe esta operación para los dos controles a la vez
seleccionándolos con la tecla [Ctrl] del teclado.

Ahora defina algunas propiedades de estos dos botones de opción.

 Siempre con un clic en el botón secundario del ratón, elija Propiedades en el


menú contextual. Introduzca los valores apropiados para el primer y el segundo
botón de opción.

o Para el primer botón de opción:

Name = OptClasApeNom
Caption = Clasificación por Apellido/Nombre

o Para el segundo botón de opción:

Name = OptNivel

Caption = Clasificación por Nivel

Las siguientes propiedades serán idénticas para los dos botones de opción.

GroupName = Gestion de Perfiles

Define la pertenencia de estos dos controles a un mismo grupo de controles. Es una


propiedad importante ya que permite gestionar la elección exclusiva entre los diferentes
botones de opción. Por defecto, se le atribuye el nombre por defecto de la hoja de
trabajo.

Height, Width, Left y Top definen la altura, la longitud, la distancia del control con
respecto al margen izquierdo y al margen superior. Las dimensiones deben ser idénticas.
Por el posicionamiento, sólo el margen izquierdo se debe definir para que se alineen los
controles. No ocurre lo mismo con el margen superior.

Font gestiona el tipo de letra.

Un botón permite abrir un cuadro con múltiples opciones.


Aplique las opciones tal y como aparecen en la captura de pantalla.

La propiedad Value define si el botón se ha seleccionado. En este caso, está a True.

Se puede acceder directamente a todas las propiedades de la ventana del mismo


nombre por código VBA.

Vamos a proceder a escribir el código para ordenar la lista de miembros seleccionados.

1. Ejecute la grabadora de macros para recuperar el código que permita ordenar por
el apellido y el nombre, ascendentemente.

Vea el código recuperado:

Key1 indica la primera columna a ordenar y Order1 el orden con el que se efectuará. Es
posible efectuar como máximo 3 ordenaciones a la vez. Vamos a crear un
procedimiento que permitirá ordenar entre 1 y 3 columnas. Hay que pasarle por
parámetro las dimensiones del rango de celdas a tratar, el número de columnas a tratar y
por último los encabezados de las diferentes columnas en el orden de prioridad elegido.

 Añada un nuevo procedimiento en el módulo formato de los datos contenidos en


las hojas de trabajo.
Después de haber recuperado el rango de células a tratar (StrRangoSeleccionado), hay
que seleccionar el número de columnas a tratar con el bloque de código Select Case.
Según el número de columnas a tratar (IntNumCol), el programa ejecuta diferentes
instrucciones.

Sería posible alimentar todas las propiedades de este bloque de código pasándolas en los
parámetros del procedimiento. Pero en el ámbito de este desarrollo, no es necesario
hacerlo tan complejo.

Sólo queda codificar las llamadas a la función después de la inserción de los niveles en
la hoja Gestion de perfiles y después de la consulta de la lista por el usuario con los
botones de opción.

 Inserte el siguiente código en CmdListaPerfiles_Click, después de la llamada al


procedimiento Call InsercionNivel (creación de la columna de niveles) y de la
descongelación de la pantalla.
Por defecto cuando se crea la tabla, se ordenan las columnas B y C. Se trata del apellido
y el nombre. El botón de opción OptClasApeNom (Ordenar por Apellido - Nombre) se
selecciona por código: OptClasApeNom.Value.

Cuando durante la consulta el usuario decide modificar el orden de la tabla, hace clic en
una de los dos botones de opción. Hay que generar el evento Click de los dos controles.
Es posible acceder a estos eventos a través del menú contextual (clic derecho) de los
controles a nivel de la hoja Gestion de perfiles. Puede también utilizar en el IDE la lista
desplegable de los objetos del libro. Si selecciona OptNivel, la lista de eventos
disponibles se posiciona por defecto en el evento Click.

El procedimiento Private Sub OptNivel_Click() - End Sub se crea en el IDE. Sólo queda
llamar al procedimiento OrdLista con los parámetros esperados.

 Inserte el siguiente código para los dos botones de opción OptNivel y


OptClasApeNom.

Si la lista está vacía, el programa sale del procedimiento.

 Puede probar el código.

Visualización de estadísticas por habilidades con gestión de


errores en el procedimiento
Vamos a visualizar resultados de cálculo en porcentaje referentes a los perfiles por
competencia. La presentación de los resultados al usuario se hará con un cuadro de
mensajes. En el procedimiento asociado a esta nueva funcionalidad, olvidaremos
voluntariamente algún trozo de código para generar errores de compilación del
programa. Veremos entonces cómo gestionar la interrupción del programa.

1. Creación del procedimiento de visualización de


estadísticas
 Cree en la hoja Gestion de perfiles un nuevo botón llamado CmdEsta para el
programa y Estadísticas como nombre visible.

 En el procedimiento vinculado al evento Click, inserte el siguiente código:


Inicialmente, hay que declarar las variables locales que servirán para almacenar los
diferentes valores de los cálculos. El tipo Integer se utiliza en los cálculos sencillos, el
tipo Single para los cálculos de porcentaje con decimales y por último el tipo String
para los resultados formateados como porcentaje.

La variable i de tipo Integer se utiliza como contador de un procedimiento al otro. Así


pues, se declara en el módulo ModDeclaracion.

Un primer cálculo del porcentaje de perfiles seleccionados para la competencia esperada


se almacena en una variable a la espera de visualizarse en el cuadro de mensajes.

La cuenta por nivel para el cálculo de la parte porcentual de los niveles de una habilidad
se hace con un Select Case. Si el contador es diferente de 0, el resultado se formatea a
través de la función Format, en caso contrario la palabra "Ningún" reemplaza el
resultado.
En el mensaje mostrado al usuario, los saltos de línea segmentan y agrupan la
información a fin de facilitar su lectura y su interpretación.

2. Los errores de compilación


 Haga clic en el botón Estadísticas para ejecutar el código.

En el momento de la compilación del programa, VBA detecta un error y bloquea el


desplazamiento del código. En el ejemplo, se trata de una variable de la que se ha
omitido su declaración. La instrucción Option Explicit del inicio de la hoja impide la
utilización de variables no declaradas. La variable se resalta. Si hace clic en el botón
Ayuda, la ayuda en línea le muestra una explicación relacionada con el tipo de error
detectado.

 Haga clic en el botón Aceptar y detenga el programa. Inserte la declaración Dim


IntNumInscritos As Integer a continuación de las otras declaraciones de
variables.

3. La depuración del procedimiento y los errores de


ejecución
 Haga clic de nuevo en el botón Estadísticas.

Esta vez la ejecución del procedimiento comienza pero se para durante la ejecución del
código (Error de ejecución). Un mensaje indica un problema de división por 0, que es
un error grave en el lenguaje VB.
Si hace clic en el botón Finalizar, parará el programa. Hay que ejecutar el procedimiento
en modo depuración. En lugar de utilizar la tecla [F5] del teclado, pulse [F8]. La lectura
de las instrucciones se hará entonces paso a paso. Esto permite, posicionando el cursor
sobre cada variable, comprobar su valor y situar la instrucción exacta en la que se para
la ejecución.

Si hace clic el botón Depurar, se resalta la línea de código en la que el programa


encuentra un problema.

Se trata de la línea de código SgPorcentInscritos = (IntNumHabilidad /


IntNumInscritos). La variable IntNumInscritos no se ha informado y por defecto se
inicializa a 0 y cumple la función de divisor en el cálculo del porcentaje de perfiles
seleccionados respecto al número total de inscritos.

 Detenga el modo depuración e inserte el siguiente código a continuación de la


declaración de variables:

A partir de la celda A1, se recupera el número de la última fila. Pero tratándose de la


lista que está en la hoja Lista de inscritos, debemos indicarlo con Sheets("Lista de
inscritos"). De este modo el número de la última fila devuelta es de la hoja Lista de
inscritos incluso si la hoja activa actual es Gestion de Perfiles. Al final de la instrucción
se añade -1 porque la primera fila de la lista es la fila de título de las columnas y no se
debe tener en cuenta.

El hecho de poder apuntar a una celda de una hoja de un libro que no esté activo,
evita las idas y venidas y la utilización de la propiedad ScreenUpdating.

Este procedimiento llama a una jerarquía de objetos o de controles que pueden ser
"padre" o "hijos" los unos de los otros.

 Pruebe de nuevo el recuento de estadísticas.


El mensaje visualiza correctamente el resultado correspondiente a la lista cargada para
la habilidad Soldador.

4. La gestión de errores
Siempre se puede producir un error a pesar de las pruebas efectuadas antes del
despliegue de una aplicación. Pero la aparición de mensajes de error o la interrupción
brusca del programa causan mal efecto a ojos del usuario. Además, los parones
intempestivos pueden ocasionar pérdidas de datos o de trabajos que se están validando.

Es posible gestionar estos errores informando al usuario de un problema con un mensaje


explícito y sin ponerlo en modo depuración.

Una gestión eficaz de los errores permite seguir teniendo credibilidad a ojos del usuario,
incluso si la aplicación se bloquea.

 Con el fin de provocar un error, vacíe la lista de los perfiles seleccionados


manualmente o seleccionando una habilidad inexistente en la lista o el botón
Cancelar del InputBox.
 Comente la línea de código al inicio del procedimiento, If Range("B6").Value =
"" Then Exit Sub y vuelva a ejecutar el procedimiento.

Aparecerá el siguiente mensaje:


Una manera eficaz de gestionar este tipo de problema es capturar el error para tratarlo
mejor.

 Haga clic en el botón Finalizar e inserte el siguiente código al principio del


procedimiento, antes de la comprobación del contenido que ha comentado.

Esta instrucción permite enviar cualquier error en el código a una etiqueta llamada
TratarError que vamos a insertar al final del procedimiento.

 Inserte el siguiente código antes de End Sub.

En este ejemplo, el número de error (gracias al objeto Err y una de sus propiedades Number)
se muestra al usuario que podrá indicarlo a informática. El mensaje también indica que se ha
interrumpido el proceso pero la aplicación está activa todavía.

El problema, sin embargo, no se ha solucionado.

 Antes de proseguir, no olvide reactivar la línea de código al inicio del


procedimiento If Range("B6").Value = "" Then Exit Sub.

A título de información complementaria, la instrucción Resume permite en la gestión


de errores retomar el programa en la línea de código donde tuvo lugar el error, mientras
que la instrucción Resume Next ignora el código erróneo y pasa a la línea siguiente.

Copias de seguridad del proyecto Gestión de perfiles


A lo largo de la progresión de la implementación del código, es necesario hacer copias
de seguridad regulares de sus trabajos. Es posible efectuarlas en forma de archivos
datados en un instante concreto con el estado de avance en el momento de la grabación.
Para esto, el lenguaje VBA tiene instrucciones que permiten la manipulación de
archivos y de directorios.

Además, el proceso de copia de seguridad no se hace únicamente a nivel global de libro


sino también a nivel de los diferentes módulos de un proyecto VBA del IDE.

1. Las operaciones de directorios en VBA


Vea las instrucciones comúnmente utilizadas en el manejo de archivos y de directorios:

 ChDir cambia el directorio de trabajo. Una vez definido el destino, no es


necesario repetir la instrucción en cada operación.
 Dir comprueba la existencia de un archivo o de un directorio.
 RmDir elimina un directorio del disco duro.
 MkDir crea un nuevo directorio en el disco.
 Kill elimina un archivo. Para eliminar un directorio es necesario eliminar el
posible contenido con esta instrucción.
 Open abre un archivo.
 FileCopy copia un archivo.
 Close cierra el archivo abierto.

2. Exportación e importación de módulos


A veces es necesario exportar diferentes módulos, tanto si se trata de módulos clásicos,
de formularios o de hojas de trabajo. Esta operación permite hacer copias de seguridad
del código y en caso de algún problema recargar estos módulos. Además, exportando
estos módulos a un directorio, se ponen a disposición de otros programadores que
pueden importarlos en su proyecto y así recuperar el código sin tener que volver a
desarrollar esas funcionalidades.

a. Exportación a partir del libro Gestión de perfiles

 Abra un nuevo libro y llámele "Libro_Prueba". Grábelo en el directorio


Formacion VBA Excel 2010.
 En el IDE, Libro_Prueba aparece en la ventana del proyecto. Despligue el árbol
haciendo clic en el signo +.
Ahora vamos a exportar módulos a partir de Gestion de perfiles.

 Cree un nuevo directorio que llamará "Copia_seguridad_Modulos" en el


directorio Formacion VBA Excel 2010.
 Visualice el menú contextual de la ventana de proyectos haciendo clic con el
botón secundario del ratón en el módulo a exportar, Hoja3. Elija Exportar
archivo.
 Se abre un cuadro de diálogo para seleccionar el directorio destino antes de hacer clic
en el botón Guardar.

Se graba un archivo llamado Hoja3.cls en el directorio.

 Repita la operación con los módulos ThisWorkbook y ModDeclaracion.

En el directorio Copia_seguridad_Modulos, los módulos ThisWorkbook y Hoja3 tienen


la extensión .cls mientras que ModDeclaracion tiene la extensión .bas.
b. Importación de módulos en Libro_Prueba

El libro tiene como módulos sólo los objetos creador por defecto, es decir, los módulos
Hoja1, Hoja2, Hoja3 y ThisWorkbook. Ahora podemos probar la importación de
módulos a partir del directorio Copia_seguridad_Modulos.

El enfoque es sustancialmente idéntico al anterior.

 En el menú contextual, seleccione Importar archivo.

La selección de un módulo del árbol no sirve para nada.


 Se abre un cuadro de diálogo para seleccionar el archivo a importar
(ThisWorkbook.cls) antes de hacer clic en el botón Abrir.

El archivo se carga en el árbol del proyecto como módulo de clase y en el nuevo directorio del
mismo nombre. Si se selecciona el módulo de clase la zona de código está vacía. De hecho, en
él no se ha hecho ningún desarrollo en Gestion de perfiles.

 Repita la misma operación con Hoja3.cls y ModDeclaracion.bas.


Hoja3.cls se carga como módulo de clase como todo archivo con extensión .cls. Si se
selecciona, todos los procedimientos escritos en este módulo se cargan al mismo tiempo
que él.

El módulo ModDeclaracion se carga como un módulo clásico en el directorio Módulos.


El código original se carga al mismo tiempo que él.

3. Copia de seguridad de la lista de inscritos


La lista de inscritos es una lista que evolucionará con el tiempo. Para controlar las
salidas de inscritos y las nuevas llegadas a la agencia, hay que conservar una situación
de estado periódica. Para ello vamos a implementar un procedimiento de archivado con
fecha de la lista en un nuevo directorio. Este procedimiento se integrará con un botón de
archivado en la hoja Gestion de perfiles.

 Cree en la hoja Gestion de perfiles un nuevo botón que llamará CmdArchivo


para el programa y Archivado como nombre visible.
 En el procedimiento vinculado al evento Click, inserte el siguiente código:
Durante la alimentación de las variables, el nombre se concatena con la fecha del día. La
función Date devuelve la fecha del sistema. El formato por defecto devuelto dd/mm/aaaa. Por
razones de clasificación de los archivos en el directorio, el formato aaaammdd
(Format(Date,"yyyymmdd")) permite clasificar ascendente o descendentemente como en el
caso de la siguiente ilustración:
Una primera prueba verifica que el directorio existe. Si no es así, la instrucción MkDir
lo crea.

La instrucción ChDir encargada de posicionarse en el directorio, habría bastado. De


hecho, se encarga de crear los directorios que faltan en la ruta indicada.

La segunda comprobación verifica que el archivo no existe ya en el directorio, si existe


la instrucción Kill lo elimina. Se evita al usuario tener que responder a un mensaje de
Excel que le pregunta si quiere reemplazar el archivo que ya existe con ese mismo
nombre en el directorio.

La hoja Lista de inscritos se copia en un nuevo libro que se graba en el directorio


destino Archivos Lista Inscritos.

Finalmente, un mensaje confirma al usuario que el archivo se ha copiado correctamente.

Por contra, hay un procedimiento de captura de errores que avisa al usuario en caso de
error en el procedimiento de archivado.

En esta operación, el mensaje es muy importante ya que el usuario no puede


comprobar directamente el desarrollo correcto del procedimiento.

Transformación de la herramienta en ejecutable


Objetivos
La aplicación Excel, como todas las herramientas de Office, es una aplicación que pone
a disposición del usuario una multitud de funcionalidades dedicadas a la gestión de
datos. Esto es lo que da potencia a esta hoja de cálculo. Pero en el ámbito de la
aplicación Gestion de perfiles, debemos restringir esta libertad de acción para proteger
nuestros datos de entrada y salida y también para que ninguna modificación perjudique
el buen funcionamiento de esta aplicación.
Para ello, debemos dar apariencia de aplicación profesional a nuestra aplicación. Con la
ayuda de los formularios (UserForm) y de los controles del cuadro de herramientas,
vamos a implementar una IHM (Interfaz Hombre Máquina) y gestionar el acceso a los
datos y la navegación por la aplicación Gestion de perfiles.

Por medio de estos formularios, podemos crear un menú de usuario. Pero también es
posible intervenir directamente en los menús y barras de Excel para insertar nuevas
funcionalidades de la aplicación.

Vamos a implementar procedimientos de identificación, de navegación por menú, de


cálculo de subtotales y de gestión del estado de personas entre los perfiles registrados de
la agencia.

A partir de ahora, la mayor parte del diseño de los módulos o formularios se harán
insertando archivos .cls y .bas que se pueden descargar en la web que el editor dedica a este
libro.

Formularios para gestionar los candidatos


El formulario o UserForm es un objeto que se puede insertar, como los otros tipos de
módulo, haciendo clic en el botón secundario del ratón en el proyecto. Puede añadirlo
con el menú contextual.

Mientras tanto, vamos a simplificar mediante la descarga de formularios de la web.

Los formularios exportados tienen la extensión .frm.

1. Inserción de formularios y de código asociado


 Alimente las celdas A1, A2, B1 y B2 de la hoja oculta Referencias.

Estos datos corresponden al nombre de usuario y la contraseña a introducir en el


procedimiento de identificación. Por defecto, de momento sólo hay un nombre y una
sola contraseña. Con la utilización de la base de datos veremos un sistema más sólido
con una contraseña por usuario.
 Importe los archivos Frm_Identificacion.frm y Frm_Menu.frm.

Los formularios se almacenan en el directorio Hojas del árbol del proyecto. Cuando un
formulario se selecciona en la ventana de proyectos, es su aspecto, así como el de sus
controles, lo que aparece en la ventana de código.

Haciendo clic en el botón secundario del ratón en el formulario o en uno de estos


controles, puede acceder al código. Pero existen botones en la parte superior de la
ventana que gestionan la navegación entre el código y el objeto.

Permite visualizar el código y todos los procedimientos del formulario. Lo mismo


ocurre con los controles que contiene.

Permite visualizar el aspecto del objeto. De este modo es posible insertar controles a
partir del cuadro de herramientas.

 Inserte el siguiente código en el módulo ThisWorkBook:

El evento Workbook_Open carga el formulario de identificación por defecto al abrirse


el libro. El usuario no puede acceder a las funciones ni a las hojas del libro hasta que no
se haya identificado.
El evento Workbook_BeforeClose corresponde al cierre del libro por el usuario
utilizando el menú Archivo - Cerrar o Salir, pero también con el aspa ( ). Todas las
modificaciones que se han hecho en el libro se graban al cerrarse. Esto permite
responder al mensaje de confirmación de estas modificaciones.

2. Estudio del código de los formularios


Cada uno de los formularios tiene código asociado a los controles o a los eventos. Este
código implementa diversas funcionalidades como la navegación entre formularios, el
acceso a las hojas de trabajo o la grabación de las modificaciones.

a. El formulario de identificación

Frm_Identificacion es el formulario de entrada. Se visualiza al iniciarse la aplicación. El


usuario se debe identificar para acceder al menú de la aplicación.

En el procedimiento Private Sub CmdValidacionUsuario_Click() (botón Validación), el programa


comprueba en primer lugar que el usuario haya introducido correctamente el nombre de
usuario y la contraseña en las dos Cajas de texto o TextBox llamados respectivamente
TxtNombreUsuario y TxtPass. Si falta uno de los dos, se visualiza un mensaje de error y el
programa sale del procedimiento. La caja de texto del nombre recupera el foco.
El TextBox TxtPass tiene una propiedad llamada PasswordChar que permite ocultar la
entrada del usuario. Basta con especificar el carácter que quiere que aparezca en lugar
de lo que escriba el usuario. En el ejemplo, utilizamos el "*".

El nombre y la contraseña se comprueban a continuación se comprueban en la hoja


Referencias. La función Ucase convierte todas la cadenas de caracteres de la
comparación en mayúsculas, esto evita tener que considerar las mayúsculas/minúsculas
en las entradas del usuario. Si existe la menor divergencia entre el nombre de usuario y
la contraseña introducidos y los de la hoja Referencias, un mensaje informa al usuario.
Además, las dos cajas de texto se vacían y antes del salir del procedimiento,
TxtNombreUsuario recupera el foco.

Si el programa no detecta ninguna diferencia en la introducción, Frm_Identificacion se


descarga y se carga Frm_Menu.

El procedimiento Private Sub CmdSalir_Click (botón Salir) cierra la aplicación sin cerrar Excel, lo
que hubiera pasado con la instrucción Application.Quit. Se comienza por descargar
Frm_Identificacion y a continuación se cierra el libro activo ThisWorkBook sin grabar las
modificaciones ya que en este momento de la aplicación, el usuario no ha accedido a las
diferentes funcionalidades ni a las hojas de la aplicación.

b. El menú de usuario

Frm_Menu permite al usuario elegir entre los diferentes sub-programas de la aplicación.


El menú de momento sólo da dos opciones se irá enriqueciendo a medida que vaya
avanzando la aplicación.
En el procedimiento Private Sub CmdConsultaPerfiles_Click (botón Consulta de perfiles), el
programa descarga el formulario y activa la hoja Gestion de perfiles. Ahora el usuario tiene
acceso completo a la hoja de trabajo.

En el procedimiento Private Sub CmdSalirMenu_Click (botón Volver a identificación), el


programa descarga el formulario y carga Frm_Identificacion. El usuario debe identificarse de
nuevo si quiere acceder a las hojas de la aplicación.

Pruebe ahora la aplicación.

 Cierre el libro y vuelva a abrirlo para ir a la hoja Gestion de perfiles.

c. Gestión del cierre de los formularios

La implementación de los formularios permite gestionar el acceso a la aplicación. Con


el procedimiento de identificación, sólo las personas identificadas y con contraseña
válida pueden acceder. Sin embargo existen fallos en este sistema.

 Recargue Frm_Identificacion, cerrando y volviendo a ejecutar la aplicación o


simplemente situando el cursor en el procedimiento de evento Workbook_Open
del módulo ThisWorkBook.
 Una vez se carga el formulario Frm_Identificacion, haga clic en el botón del
formulario que se va a cerrar dando acceso a las hojas del libro.

Hay que desactivar el botón de cierre del formulario para que la introducción de la
contraseña sea obligatoria para acceder a la aplicación.

 Inserte el siguiente procedimiento en Frm_Identificacion.


Este procedimiento UserForm_QueryClose corresponde al momento anterior al cierre
del formulario. CloseMode = 0 determina que se ha hecho clic en el aspa. El formulario
se mantiene activo sin modificar ya que la propiedad Cancel está a True.

 Vuelva a ejecutar Frm_Identificacion y compruebe el cierre del formulario con


el aspa. Este comando se ha desactivado.
 Inserte el procedimiento de forma idéntica en Frm_Menu y haga la misma
prueba para este formulario.

d. La aplicación Gestión de perfiles se convierte en un ejecutable

En el capítulo Gestión de la aplicación con una base de datos veremos que con la
identificación es posible recuperar su nivel de acceso sobre la aplicación. Esto significa
que un usuario tendrá acceso a diferentes funcionalidades o menús de esta aplicación en
función de sus permisos. En este caso, no hay que dejar ver al fondo una hoja que puede
tener datos para los que no tiene acceso.

 Inserte en el procedimiento de evento Workbook_Open del módulo


ThisWorkBook justo antes de la instrucción de carga de Frm_Identificacion, el
siguiente código:

 Siempre en el procedimiento de evento Workbook_Open, inserte el siguiente


procedimiento:

Al abrir el libro, la propiedad IsAddin del objeto ThisWorkbook se pone a True. Las
hojas de trabajo no se pueden ver ni acceder. No es posible abrir el IDE mientras la
propiedad está activada. Se crea un nuevo procedimiento
Workbook_WindowDeactivate para determinar el momento en que el libro Gestion de
perfiles no está activo. Esto ocurre por el cierre de este último por el usuario o por la
selección de otro libro abierto. La propiedad IsAddin pasa a False.
Antes de probar la aplicación, hay que tener en cuenta el hecho de que las hojas del
libro no están accesibles. En la validación de los datos entrados por el usuario, la
propiedad IsAddin debe estar a False y luego volver a True mientras el programa vaya a
consultar la hoja Referencias. Esto permite evitar el siguiente mensaje de error:

 Modifique el bloque de código que valida el nombre de usuario y la contraseña en el


procedimiento de evento Private Sub CmdValidacionUsuario_Click del formulario
Frm_Identificacion :

Si la identificación no es válida, no hay que olvidar de poner la propiedad IsAddin a


True. Mientras se ejecutan estas instrucciones, la pantalla está congelada para ocultar la
aparición de las hojas del libro.

 Puede probar el libro cerrándolo sin tener que grabar sus modificaciones, ya que
el procedimiento de evento Workbook_BeforeClose del módulo ThisWorkBook
lo hace automáticamente.
El resultado en la pantalla corresponde a lo que esperamos pero, a pesar de todo, queda
un problema. En la carga del libro, justo antes de que el programa ponga la propiedad
IsAddin a True, aparece fugazmente la última hoja activa del libro.

 Inserte una nueva hoja en el libro que llamará Inicio.


 En el menú Archivo - Opciones del libro, desactive la cuadrícula de esta hoja en
la sección Mostrar opciones para esta hoja de la pestaña Avanzadas. Esta hoja
debe quedar desprovista de cualquier dato.
 En el procedimiento Private Sub Workbook_BeforeClose, inserte la línea de
código Sheets("Inicio").Select antes de la instrucción de grabación del libro. En
cada cierre del libro, la hoja Inicio pasa a ser la hoja activa del libro.

Es probable que esté habituado en las aplicaciones que utiliza cotidianamente a activar
un botón por defecto con la tecla [Intro] del teclado. Es lo que va a hacer en los
formularios Frm_Identificacion y Frm_Menu.

 Ponga a True la propiedad Default de los botones de comando


CmdValidacionUsuario y CmdSalirMenu. Ahora, la tecla [Intro] emula al botón
Validación en el formulario de identificación y el botón Volver a identificación
en el menú.
 Pruebe de nuevo Gestion de perfiles.

Presentación del objeto Formulario y de los principales controles


del cuadro de herramientas
El IHM es un conjunto de formularios que soportan cada uno de los controles. Este
conjunto inicia el diálogo entre el usuario y las funcionalidades de la aplicación.
Todos los objetos que constituyen la interfaz tienen propiedades, métodos y eventos
propios. Es posible actuar sobre estas propiedades al crearlas en la ventana Propiedades
o durante la utilización con instrucciones diseminadas en el código del programa. El
aspecto de los diferentes controles se determina con el método de hacer clic - arrastrar
(Drag and Drop) con los tiradores que los rodean cuando están seleccionados. Lo
mismo ocurre con su posición dentro de su contenedor (un Formulario).

1. El formulario o UserForm
Vamos a ver las principales propiedades, los principales métodos y los principales
eventos del formulario.

 Ejemplo de propiedades

Name: nombre de la hoja que reconoce el programa.

Caption: título de la hoja que aparece en la barra de título.

ShowModal: esta propiedad puede tomar el valor True o False. Indica si el


formulario está abierto en modo modal. Si es así cuando está activo, el usuario
no puede acceder a elementos de fuera del formulario con el ratón.

 Ejemplo de métodos

Show: carga del formulario.

Hide: el formulario es invisible pero queda cargado en memoria.

Repaint: actualización del formulario que se ha redibujado.

 Ejemplo de eventos

Activate: el formulario obtiene el foco. Se convierte en el formulario activo.

Deactivate: el formulario pierde el foco.

Load: carga en memoria del formulario que no tiene porqué estar visible.

Unload: descarga del formulario de la memoria.

2. Los controles del cuadro de herramientas


Los controles del cuadro de herramientas se insertan en los formularios siempre por el
método de hacer clic - arrastrar y a continuación se ajustan.

a. Las propiedades y los eventos comunes

Existen propiedades comunes a la mayor parte de los controles del cuadro de


herramientas.
Ejemplo de propiedades comunes

Name: nombre del control que reconoce el programa.

Caption: título o etiqueta visible del control.

Text: etiqueta o cadena de caracteres visible del control.

BackColor : color de fondo del control.

ForeColor: color de los caracteres.

Font: abre un cuadro de diálogo de gestión de fuentes.

Enabled: gestiona la disponibilidad de un control. La propiedad puede estar a True o a


False.

Locked: bloquea el control cuando la propiedad está a True.

Visible: el control es visible (True) o invisible (False).

TabIndex: gestiona el orden de acceso a los diferentes controles a través del tabulador.

Height: altura del control.

Width: longitud del control.

Left: distancia respecto al margen izquierdo.

Top: distancia respecto al margen derecho.


MousePointer: gestiona el aspecto del cursor del ratón cuando pasa sobre el control.

Ejemplo de eventos comunes

Click: corresponde a un clic del ratón del usuario sobre el control.

DblClick: corresponde a un doble clic del ratón del usuario sobre el control.

Change: se desencadena cuando hay un cambio en el contenido del control.

Enter: cuando se recibe el foco.

Exit: cuando se pierde el foco.

KeyPress: cuando se presiona una tecla del teclado.

b. Presentación de los controles

A continuación se presentan los controles disponibles por defecto en el cuadro de


herramientas. Vamos a ver sus principales propiedades.

Selecciona, desplaza y redimensiona los controles.

Etiqueta o Label que muestra un texto (propiedad Caption) no modificable por


el usuario. Permite crear etiquetas asociadas a controles o mostrar resultados no
modificables.

El cuadro de texto o TextBox permite la introducción y visualización de datos


alfanuméricos y numéricos.

Text: almacena los datos introducidos por el usuario o los muestra.

MaxLength: fija un número límite de caracteres a introducir.

PasswordChar: define el carácter que se mostrará en la introducción de contraseñas.

El cuadro combinado o ComboBox permite mostrar elementos de una lista


desplegable en la que el usuario puede seleccionar uno. En principio, mientras el
usuario no despliegue la lista, sólo aparece un elemento en la zona de texto.

ListCount: devuelve el número de elementos de la lista.

ListIndex: permite definir o enviar el índice del elemento seleccionado. Por defecto el
índice está a 0 para el primer elemento de la lista. Si no hay ningún elemento
seleccionado, el índice devuelve el valor -1.
Sorted: ordena la lista por orden alfabético.

AddItem: permite añadir elementos a la lista.

RemoveItem: permite eliminar elementos de la lista.

Clear: limpia todos los elementos de la lista.

El cuadro de lista o ListBox muestra una lista de elementos en la que el usuario


puede seleccionar uno.

ListCount: devuelve el número de elementos de la lista.

ListIndex: permite definir o enviar el índice del elemento seleccionado. Por defecto el
índice está a 0 para el primer elemento de la lista. Si no hay ningún elemento
seleccionado, el índice devuelve el valor -1.

Sorted: ordena la lista por orden alfabético.

AddItem: permite añadir elementos a la lista.

RemoveItem: permite eliminar elementos de la lista.

Clear: limpia todos los elementos de la lista.

La casilla de verificación o CheckBox permite al usuario hacer una o más


selecciones en una lista de opciones.

Value: determina si la casilla se ha seleccionado (propiedad a True).

El botón de opción o OptionButton (o incluso botón radio) permite al usuario


hacer una selección única entre una lista de opciones.

Value: determina si el botón está seleccionado por defecto (propiedad a True).

Index: permite identificar el botón en el grupo de opciones.

El botón de alternar o ToggleButton permite mostrar el estado de selección de


este botón y la ejecución efectiva o no del procedimiento asociado a este botón.

Value: define el estado de selección por defecto (propiedad a True si se selecciona el


control).
El marco o Frame crea un contenedor donde es posible agrupar otros controles
como los botones de opción o las casillas de verificación.

El botón de comando o CommandButton define un botón al que se asocia un


procedimiento.

Default: define el botón como botón por defecto activado por la tecla [Intro] (propiedad
a True).

Cancel: anula las modificaciones realizadas en el formulario activo (propiedad a True).

La barra de tabulaciones o TabStrip permite utilizar controles relacionados. Se


trata de los mismos controles utilizados de una pestaña a la otra. Cada pestaña
representa un dato clave del que depende la alimentación de los controles relacionados.

La Página múltiple permite trabajar con un gran volumen de controles que se


pueden repartir en las diferentes pestañas del formulario.

La barra de desplazamiento o ScrollBar permite desplazarse en una lista.

El botón de número o SpinButton incrementa y decrementa números.

El control Imagen muestra una imagen o un icono.

El control RefEdit recupera las direcciones de un rango de celdas después que el


usuario las seleccione en una o más hoja(s) de cálculo.

Es posible añadir controles en el cuadro de herramientas. Sólo hay que mostrar


un menú contextual haciendo clic en el botón secundario del ratón en la caja.
Después de haber seleccionado Controles suplementarios, basta con elegir un
control disponible en la lista.
Según el control que elija, se instala un archivo OCX a nivel de sistema operativo. Si
luego debe desplegar la aplicación, compruebe que el archivo OCX está
correctamente instalado en los ordenadores en los que se instalará la aplicación.

Creación de subtotales en la lista de inscritos


Los subtotales de la lista de inscritos nos permitirán efectuar un recuento de individuos
por profesión. Esta nueva funcionalidad se gestionará en un conjunto de
menús/submenús que creará automáticamente por el lenguaje VBA y se suprimirá al
cerrarse la aplicación.

 Importe los ficheros Frm_Seleccion.frm y ModMenus.bas.

1. La gestión de los menús


La gestión de los menús en este párrafo afecta a las barras de menú de Excel así como
los menús que las componen.

a. Eliminación de las barras de Excel en la hoja Inicio

Para reducir las posibilidades de acciones en la hoja Inicio, vamos a eliminar las barras
de herramientas.

 Inserte el siguiente código en la hoja Inicio:


En la activación de la hoja se eliminan las barras. Esta eliminación afecta a todo Excel
sea cual sea la hoja activa. No olvide volver a mostrar las barras de herramientas
eliminadas cuando se desactiva la hoja Inicio.

El procedimiento GestionBarras del módulo ModMenus gestiona la carga y la descarga


de las barras de fórmulas y de estado, de los encabezamientos de columnas y de filas.

La activación se hace con los valores de tipo booleano True o False. Sus equivalentes
numéricos son 1 y 0. En la llamada al procedimiento, el valor 0 se pasa por parámetro
para desactivar las barras.

Respecto a los valores booleanos, 0 se utiliza como False mientras que cualquier
valor diferente de 0 puede ser True.

Vea la hoja sin estos atributos habituales como la barra de fórmula, la barra de estado, la
cuadrícula y los encabezados de fila y columna.
b. La creación del menú Gestión de perfiles

La aplicación va a poner a disposición del usuario un conjunto de menús/submenús.


Este conjunto se va integrar en la barra de menús clásicos como Archivo, Edición...

El procedimiento InsertarMenu del módulo ModMenus se encarga de crear el menú.

For Each - Next, revisa todos los menús activos en Excel y los identifica por su
propiedad Caption (nombre visible). Si el menú existe, el programa sale del
procedimiento. La instrucción Each permite recorrer todos los controles contenidos en
un objeto. En este caso se trata de los controles de Menús de Excel:
MenuBars(xlWorksheet).Menus. La variable Cmd de tipo objeto se declara en el
encabezado del módulo ya que se utiliza en diversos procedimientos.

El menú Gestión de perfiles se crea así como los submenús asociados. La propiedad
OnAction vincula el submenú (MenuItems) a un procedimiento que se ejecutará por la
selección del usuario.
c. La eliminación del menú Gestión de Perfiles

Una vez se insertado el menú en Excel, es necesario prever un procedimiento de


desinstalación. De hecho, este menú es propio de esta aplicación y se debe eliminar al
cerrarse el libro.

El procedimiento EliminarMenu del módulo ModMenus se encarga de eliminar el


menú.

Igual que en el principio del procedimiento InsertarMenu, se busca el menú Gestión de


Perfiles para eliminarlo. Cuando se elimina, el programa sale del bucle con la
instrucción Exit For.

d. Gestión de eventos del menú

La inserción y eliminación del menú se hacen al abrir y cerrar el libro. Estos son los
procesos de eventos del módulo ThisWorkbook que se van a utilizar de nuevo.

 Inserte al inicio del procedimiento Private Sub Workbook_Open el código Call


InsertartMenu.
 Inserte al inicio del procedimiento Private Sub Workbook_BeforeClose el
código Call EliminarMenu.

Puede ahora probar la aplicación ya sea cerrando y volviéndola a abrir a continuación


para generar el evento Workbook_Open, o bien colocando el cursor en el IDE en el
mismo procedimiento y pulse a la tecla [F5] en el teclado.

El menú y sus submenús asociados aparecen en la pestaña Complementos a


continuación de las otras en la barra de menús de Excel.

2. Los subtotales de la lista de inscritos


Ahora vamos a centrarnos en el desarrollo de los procedimientos llamados por los
menús y la propiedad OnAction.

a. El submenú Subtotales por profesiones

El submenú ejecuta el procedimiento SubTotales del módulo ModMenus.

El procedimiento se inicia con una llamada a un procedimiento llamado EliminarHoja.


De hecho, antes de crear la hoja Subtotal por profesión que es la hoja a partir de la cual
se visualizarán los subtotales, hay que comprobar que no está ya en el libro. Esta
situación es posible que se produzca ya que el usuario puede emular cuando quiera la
creación de estos subtotales durante la sesión de trabajo.

 Inserte el procedimiento el procedimiento EliminarHoja en el módulo


ModGestionLibro.

El nombre de la hoja a eliminar se pasa por parámetro. El bucle de tipo For - Next
permite comprobar la existencia de la hoja. Si llega el caso, se elimina desactivando los
mensajes de alerta durante la eliminación y el programa sale del bucle.
b. Estudio de la función de comprobación de carga del formulario Frm_Seleccion

Una vez completado el procedimiento, hay que continuar con el procedimiento


Subtotales. La hoja Lista de inscritos se copia y renombra como Subtotal por profesión.
El formulario Frm_Seleccion se carga siempre que no esté abierto. Esta situación es
muy posible en el caso de una entrada no válida de rango de celdas. Como veremos a
continuación en el estudio del procedimiento CmdValidacionRango_Click del
formulario Frm_Seleccion, el procedimiento SubTotales se vuelve a ejecutar siempre
que el formulario esté activo. No es necesario volver a cargarlo. Esto es lo que prueba la
función F_FormCargado. La llamada a esta función se hace a través de la línea de
código If F_FormLoaded(Frm_Seleccion.Name) Then. La función recupera el nombre
del formulario a comprobar y envía el valor True si la hoja está visible y el valor False
en caso contrario.

En el tipo de comprobación If Frm_Seleccion.Visible Then, la línea de código se


debería escribir If Frm_Seleccion.Visible = true Then pero es posible abreviar por
el valor True. Eso no sería posible si el valor es False.

c. La herramienta de selección de rango de celdas

Con el control RefEdit (que en el programa se llama RfdRangoCeldas) el usuario puede


seleccionar un rango de celdas en la lista de inscritos (la lista completa o un extracto de
algunas filas). Esta lista debe ser un único bloque y no es posible seleccionar filas
separadas con la tecla [Ctrl] presionada. Después de un clic en el botón Validar, se
calculan los subtotales y se insertan a partir de la selección del usuario.

El botón Salir cierra el formulario. La hoja Selección por profesión se elimina previamente. El
cierre con el aspa se deshabilita como en otros formularios de la aplicación.
El botón Validar ejecuta la implementación de los subtotales.
El procedimiento se inicia con una instrucción de captura de errores que envía a una
etiqueta llamada TratarError. La variable StrRango se declara localmente en el
encabezado del procedimiento ya que no es necesario que se vea desde ningún otro
procedimiento. A continuación se comprueba la entrada de usuario y se sale de
procedimiento si no se ha introducido ningún rango.

En este momento, el rango introducido, se recupera con RfdRangoCeldas.Value (ej. :


"Subtotal por profesión’!$A$1:$E$83"). Se le da formato para guardar sólo el rango de
celdas ignorando la hoja de trabajo de la que dependen (ej.: "$A$1:$E$83"). La función
VBA InStr da la posición del primer carácter $ que compone la dirección. Esta
información permitirá, con una combinación de la funciones Mid, Len y de la variable i,
cargar la cadena de caracteres esperada en StrRango.

La función Replace sustituye una referencia a la celda A1 ($A$1) por la celda A2


($A$2) si la encuentra. Esta operación es necesaria ya que para efectuar la ordenación
de la selección, hay que excluir la primera línea que engloba los encabezados de la
columnas.

El programa excluye a continuación todas las filas que no forman parte de la selección
del usuario.

El rango ahora está ordenado por profesión y por nivel. Estos grupos son necesarios
para el cálculo de los subtotales.

Ahora hay que insertar los subtotales en la lista. Esta vez, la barra de título se incluye en
la lista seleccionada: Range("A1:E" & Range("A2").End(xlDown).Row).Select. El
método Subtotal se aplica a la selección con opciones de formato del resultado:

GroupBy:=3: los grupos se hacen a partir de la columna ordenada de profesiones.

Function:=xlCount: es un número total de elementos devuelto.

TotalList:=Array(3): el resultado se muestra en la columna de profesiones después de


cada grupo.

Si el proceso funciona correctamente, se descarga el formulario Frm_Seleccion. En el


caso de una selección no válida, se intercepta un error y el programa se desvía a la
etiqueta TratarError.

Si se trata de un error de tipo 1004 (datos no válidos), se informa al usuario con un


mensaje. El procedimiento SubTotales se vuelve a ejecutar para recuperar una copia sin
modificar de la lista de inscritos. El formulario Frm_Seleccion queda activo esperando
una nueva selección del usuario. De este modo, la función F_FormCargado comprueba
si el formulario está activo antes de cargarlo.

 Puede probar el menú de creación de subtotales.


3. El retorno al formulario Frm_Menu y el cierre de la
aplicación
Los submenús restantes se utilizan para la navegación en la aplicación y no tienen una
gran complejidad.

a. El submenú Volver al menú

Este submenú permite al usuario volver al formulario del menú principal. Ejecuta el
procedimiento Menu_CargaMenu del módulo ModMenus.
La hoja Subtotal por profesión se elimina llamando al procedimiento EliminarHoja.
Antes de cargar Frm_Menu, se vuelve a activar la propiedad IsAddin.

b. El submenú Cerrar la aplicación

Este submenú permite al usuario cerrar la aplicación sin cerrar Excel. Ejecuta el
procedimiento Menu_CerrarAplicacion del módulo ModMenus.

Un mensaje pregunta al usuario que confirme el cierre de la aplicación. El cuadro de diálogo


propone una elección al usuario que habrá que gestionar por código.

 Inserte a continuación del código en el módulo ModDeclaracion, la siguiente


declaración de variable:

La variable IntRes de tipo Integer recupera bajo la forma de un dato numérico la


elección que ha hecho el usuario. Si hace clic en el botón Cancelar, se recupera el valor
2 en la variable. Entonces el programa sale del procedimiento. Si se elige el botón
Aceptar, se recupera el valor 1. El procedimiento EliminarHoja se llama pasando la hoja
Subtotal por profesión por parámetro. Se selecciona la hoja Inicio antes de cerrar la
aplicación. Se realiza el cierre del libro guardando las modificaciones.

c. Gestión del cierre de Excel

El usuario puede elegir salir de la aplicación por el menú Excel Archivo - Cerrar o Salir
pero también con un clic en el aspa de cierre del libro.

 Inserte el siguiente código en el procedimiento de evento


Workbook_BeforeClose del módulo ThisWorkbook.

Los diferentes modos de cierre de la aplicación activan el evento Workbook_BeforeClose del


módulo ThisWorkbook y se elimina hoja Subtotal por profesión.

La gestión de estado de los miembros


Después de haber añadido menús en la barra de menús de Excel, vamos a crear nuestra
propia barra de herramientas. La única función de esta barra es permitir al usuario
ejecutar un nuevo formulario de gestión de estado de los miembros con la hoja Lista de
inscritos como origen. La recuperación de los datos de la lista se hará por diferentes
métodos tales como bucles o tablas.

1. La gestión de la barra de miembros


Con la creación de esta barra, vamos a ver cómo asignar una referencia de objeto
gracias a la instrucción Set.

a. Creación de la barra

 Inserte el procedimiento de creación y visualización de la barra, GestionBarra en


el módulo ModMenus.
Se declaran las siguientes variables:

 La variable CmdBarMiembro que se declara como CommandBar y crea una


barra de menú.
 La variable CmdBarMiembroPP que se declara como CommandBarPopup y
crea un menú integrado en la barra de menú.
 La variable CmdBarMiembroCtrl que se declara como CommandBarControl y
permite arrastrar un control en el menú.

Sus respectivas referencias de objeto se les asignan a continuación con las siguientes
propiedades asociadas:

 Para CmdBarMiembro, la propiedad Name recupera el nombre para el código


VBA de la barra de menú ("BarGestMiembro") y Position:=msoBarTop define
su posición en la parte superior del libro.
 El menú CmdBarMiembroPP se inserta en la barra de menú CmdBarMiembro.
La instrucción Type:=msoControlPopup define el tipo de menú y la propiedad
Caption muestra su nombre visible ("Miembros").
 El control CmdBarMiembroCtrl se inserta en el menú CmdBarMiembroPP. La
instrucción Type:=msoControlButton define su tipo y el icono ID:=455S se
asocia a éste último. La propiedad OnAction vincula el procedimiento
Menu_CargaGestionMiembro al control y Caption muestra su nombre visible o
título ("Gestión del estado").

Una vez creada, la barra de herramientas se muestra con la propiedad Visible a True.
b. Submenú y gestión de la barra en la aplicación

 Inserte a continuación los dos procedimientos Menu_CargaGestionMiembro y


Menu_EliminarBarra en el módulo ModMenus.

El procedimiento Menu_CargaGestionMiembro asociado al menú de la barra Miembros


sólo carga el formulario Frm_Miembros.

El procedimiento Menu_EliminarBarra elimina la barra de menú. Con un bucle de tipo


For Each - Next, se comprueban todas la barras y las que están integradas en origen en
el libro se identifican por la propiedad BuiltIn. Entonces, se eliminan.

Sólo queda gestionar las llamadas a los procedimientos para la creación y la eliminación
de la barra.

 Inserte el siguiente código en el procedimiento de evento Workbook_Open del


módulo ThisWorkbook después de Call InsertarMenu.

 Inserte el siguiente código en el procedimiento de evento Workbook_BeforeClose del


módulo ThisWorkbook después de Call EliminarMenu.
Puede probar el programa volviendo a ejecutarlo a partir del procedimiento de evento
Workbook_Open del módulo ThisWorkbook (tecla [F5]). Evite hacer clic en el menú
Gestión de estado ya que el formulario que se carga no se ha insertado todavía en el
código.

2. El formulario y el código para la gestión de estado de


los miembros
El estado de los miembros de la agencia de trabajo temporal no es algo fijo. A los
individuos de la lista se les puede pedir que cambien de profesión. También pueden, a lo
largo del tiempo, evolucionar y pasar a un nivel superior de habilidad. Por último, la
disponibilidad evoluciona constantemente en función de los trabajos y tareas.

 A partir del libro Agencia_trabajo_temporal, copie la lista de trabajos


incluyendo la primera fila de encabezado, en la hoja Referencias de la aplicación
Gestión de perfiles. Inserte la lista a partir de la celda A4.
a. Presentación del nuevo formulario y de sus controles

 Inserte el formulario Frm_Miembros.frm.


A la izquierda del formulario de encuentra un objeto de tipo ListBox (LstMiembros) en
el que se cargan los apellidos y nombres de la hoja Lista de inscritos. Un clic en la lista
selecciona un individuo. Los Combobox o listas desplegables (CboProfesiones y
CboNivel) se alimentan entonces con la profesión y el nivel correspondiente a la
selección. Lo mismo ocurre con la disponibilidad con los OptionButton o botones de
opción (OptDispoSi et OptDispoNo).

b. Estudio del código del formulario

Todos los objetos del formulario se inicializan en la carga.


Los dos ComboBox tienen su propiedad Style a fmStyleDropDownList para bloquear la
introducción de datos.

CboNivel se llena con la variable TabNivel de tipo Variant. La función Array permite
asignarle una tabla que contiene los tres niveles. La propiedad List permite asignar los
valores de una tabla a contenedores como los ComboBox o los ListBox.

Para este ejemplo, los datos se escriben por código pero este proceder se debe
evitar para poder modificarlos si es necesario.

CboProfesiones se llena a partir de una lista almacenada en la hoja Referencias. Esta lista se
revisa en un bucle Do While - Loop mientras la celda no esté vacía. El valor recogido se carga
con la propiedad AddItem.
Hay que tener cuidado de no provocar un bucle infinito en el programa. Es lo que
ocurre cuando se olvida la suma del contador (la variable i en nuestro ejemplo).
La celda que se revisa es la misma y el código no puede salir del bucle. Si el
programa entra en un bucle, puede utilizar la combinación de teclas [Ctrl][Pausa]
para interrumpir la ejecución del código.

Para LstMiembros, se utilizan una tabla y la propiedad List. La tabla TabInscrit() de


tipo String se declara sin dar un tamaño exacto. Un bucle recorre la lista de inscritos. Al
mismo tiempo que se suma el contador i, la tabla se redimensiona (Redim) conservando
su contenido (Preserve).

Para tratar los diferentes elementos de la tabla, se utiliza el índice. Por defecto,
inicialmente el índice es 0 pero la instrucción Option Base 1 en el encabezamiento del
código del formulario da el valor 1 al primer elemento de la tabla TabInscrit().

La llamada al procedimiento Sub DetalleMiembro(LstMiembros.ListIndex + 2) permite la carga


de los comboBox y seleccionar la OptionButton del Frame Disponibilidad que corresponde al
estado. Los valores se recuperan a partir de la hoja Lista de inscritos.

El procedimiento de evento LstMiembros_Click() modifica la selección en el ListBox y


carga el estado asociado por la llamada a DetalleMiembro. El índice que se pasa al
procedimiento se aumenta en 2 unidades porque el ListBox no se ve afectado por la
instrucción Option Base 1 y la lista comienza en la segunda fila de la hoja, ya que la
primera está reservada al encabezado de las columnas.

El botón Validar está deshabilitado en la carga del formulario ya que la propiedad


Enabled está a False. Cuando la propiedad pasa a True, el botón está disponible de
nuevo. Esto ocurre cuando el usuario efectúa una modificación del estado introduciendo
un nuevo valor de profesión, cambiando el nivel en los comboBox o haciendo clic en
uno de los OptionButton del Frame Disponibilidad. Para estos tres controles, el evento
Change guarda las modificaciones del usuario y la propiedad Enabled pasa entonces a
False.

Si el botón Validar está habilitado, es posible registrar las modificaciones realizadas por el
usuario.

En este caso, el programa pide al usuario que responda a la siguiente pregunta.


En caso de confirmar con el botón Si, los datos se graban en la hoja Lista de inscritos.

Si el usuario escoge el botón No, los detalles del estado del miembro se vuelven a
cargar con el procedimiento DetalleMiembro.

Si el usuario escoge el botón Cancelar, el proceso se interrumpe y el código sale del


procedimiento con la instrucción Exit Sub.

El botón Validación se habilita de nuevo salvo en el caso de una interrupción del


proceso.

El botón Salir permite descargar el formulario. La instrucción Me representa por defecto


Frm_Miembros.

En esta ocasión, el cierre con el aspa no se deshabilita.

Ahora puede probar la barra de menú y el formulario Frm_Miembros.

Transformación de la herramienta en ejecutable


Objetivos
Vamos ahora a desarrollar una nueva funcionalidad dedicada a la creación del
calendario. Por cada nuevo trabajo registrado en la agencia de trabajo temporal, el
usuario asigna los inscritos disponibles. En ese momento se integran en un calendario.

Cada integración en este calendario corresponde a una tarea. Cada una de estas tareas se
vincula el apellido, el nombre y la profesión del individuo afectado. Sólo se puede
considerar a los individuos disponibles para un trabajo. Se asocia una fecha de inicio de
tarea a un número de días asignados. La fecha final se calcula entonces en función de un
calendario en el que se tendrá en cuenta los días laborables y no laborables. Toda esta
información se convertirá en un histograma en el que cada barra está vinculada a una
tarea asociada al trabajo en curso.

La creación de un nuevo trabajo pasa por la carga de un nuevo calendario a partir del
directorio Plantillas. Una vez se introduce el trabajo y el nombre del cliente, el usuario
puede grabarla en un directorio con el nombre del cliente en el directorio Trabajos.

Este capítulo permitirá introducirse un poco más en el algoritmo y la lógica de un


desarrollo clásico en VBA. Por medio de bucles y de condiciones anidadas, se gestionan
los datos introducidos por el usuario y se efectúan cálculos para obtener un informe
correcto en el histograma.
La navegación con formularios, los menús y las hojas ocultas se van a extender al
conjunto de la aplicación.

Extensión de los procesos de navegación al conjunto de la


aplicación Gestión de perfiles
A partir de aquí, las hojas de trabajo deben ser accesibles y visibles sólo a través del
formulario Frm_Menu. Sería peligroso para la estabilidad de la aplicación permitir al
usuario modificar el estado de los miembros seleccionándolos para asignarlos a un
nuevo trabajo. Sólo debe quedar visible la hoja Inicio justo detrás de los formularios de
navegación.

Es necesario ocultar las hojas Gestion de perfiles y Lista de inscritos que se convierten
en hojas de referencia del proyecto. Para ello, hay que asegurarse que en cada referencia
en el programa a una de estas hojas se pueda acceder a ellas y que su propiedad Visible
sea True. Por el contrario, al volver al formulario de menú o al salir de la aplicación, su
propiedad Visible debe entonces pasar a False.

1. La hoja Gestión de perfiles


 Inserte el código Sheets("Gestion de perfiles").Visible = True justo antes de la
instrucción de selección (Select) de la hoja en el procedimiento
CmdConsultaPerfiles_Click en Frm_Menu.
 Inserte el código Sheets("Gestion de perfiles").Visible = False justo antes de la
selección de la hoja Inicio en el menú Menu_SalirAplicacion en ModMenus.
 Inserte el código el código igual como se indica pero añadiendo una
comprobación antes de mostrar la hoja Gestion de perfiles.

 Sitúe este bloque de código justo antes de las llamadas a procedimientos para la
eliminación de menús y de barras en:
 Menu_CargaMenu en ModMenus.
 Workbook_BeforeClose en ThisWorkbook.

2. La hoja Lista de inscritos


 Inserte el código Sheets("Lista de inscritos").Visible = True y después
Sheets("Lista de inscritos").Visible = False en:
 El procedimiento SubTotales de ModMenus en la copia de datos y la
creación de la hoja Subtotal por profesion.

 La hoja Gestion de perfiles en que están afectados más procedimientos:
1. CmdArchivo_Click en la copia de la hoja y después su grabación
en el directorio destino.
2. CargaListaPerfiles antes de la selección de la hoja Lista de
perfiles y al final del procedimiento, antes del retorno a la hoja
Gestion de perfiles.
3. InsercionNivel antes de la selección de la hoja Lista de perfiles y
justo después de la eliminación de la columna Apellido/Nombre.

 Puede probar la aplicación.

3. Inserción de nuevas hojas de trabajo y de referencia


en la aplicación
Descargue de la web del editor el libro Calendario_Trabajo.xlsm en el directorio
Plantillas. Esta nueva plantilla contiene dos hojas de trabajo que se van a cargar en el
programa para cada creación de nuevos trabajos.

 La hoja Asignación Trabajo permite al usuario redactar una lista de candidatos


susceptibles de ser asignados a un trabajo.

 La hoja Calendario Trabajo contiene el calendario del trabajo para cada candidato
asignado, las fechas de las tareas que tiene que realizar. Estas fechas y duraciones se
muestran en el histograma.
 Mueva y copie en el libro Gestion de Perfiles, la hoja de referencias Calendario del
libro Plantilla_Equipo.

Este calendario cubre para nuestra presentación todo el año 2010 hasta el 31 de
diciembre incluido. Basándose en la columna H (Fecha), puede efectuar una búsqueda a
partir de la fecha introducida por el usuario y devolver los datos correspondientes como
el número y el nombre del mes, el día de la semana, el número del día y su estado (F
para festivo o W para fin de semana).

 Copie a partir de la hoja Histograma del libro Plantilla_Equipo la zona de


informe del histograma. Seleccione el rango de celdas que va de D1 a AZ2 para
pegarla en la hoja Referencias del libro Gestion de Perfiles a partir de la celda
D1.
Este rango de celdas se insertará en cada introducción de nuevas tareas en la hoja Calendario
Trabajo.

Integración de la plantilla para la creación de trabajos


Ahora se trata de implementar los procesos que van a gestionar la carga de las hojas de
plantillas y su eliminación al retorno al menú.

1. El procedimiento de carga de las plantillas para el


calendario
 Inserte en el módulo ModGestionLibro, el siguiente procedimiento:

El procedimiento CargaCalendarioTrabajo gestiona la carga de las dos plantillas


Calendario Trabajo y Asignación Trabajo que se añaden como hojas visibles en el libro
Gestion de perfiles al lado de la hoja Inicio.

Con la instrucción FileCopy, el libro Calendario_Trabajo.xlsm se copia a partir del


directorio Plantillas a la raíz del lugar donde se encuentra almacenado Gestion de
perfiles. A continuación de la instrucción FileCopy se encuentra la ruta del fichero
origen y el directorio destino. La propiedad Path permite recuperar la ruta del archivo a
la que está asociada (ActiveWorkbook.Path o ThisWorkbook.Path).
Una vez copiado, el libro se abre localmente para copiar las dos hojas
(Sheets(Array("Calendario Trabajo", "Asignacion Trabajo")).Select), justo después de
la hoja Inicio: Copy After:= Workbooks("Gestion de perfiles").Sheets(1). El libro
plantilla se cierra sin guardar las modificaciones y se elimina su copia local. Se activa
en pantalla la hoja Asignación Trabajo.

En el ámbito de un desarrollo de la aplicación en una red, copiar el archivo origen


localmente da la posibilidad de realizar modificaciones sin tener que hacer
multitud de idas y venidas. Esto podría ser particularmente malo en un entorno
lento o inestable. Piense también en realizar pruebas de intercambio de archivos
a medida que integra en su desarrollo funcionalidades relacionadas con el flujo
de datos en importación o exportación.

2. Modificación del formulario Frm_Menu


El nuevo procedimiento debe ser accesible desde el formulario de menú.

 Inserte un nuevo botón en el formulario

Puede hacer un copiar-pegar de uno de los dos botones. Esto permite recuperar
las dimensiones idénticas a los anteriores.

 Introduzca las propiedades del siguiente modo:

Name: CmdCalendario
Caption: Creación de un calendario de trabajo

 Inserte el código asociado al evento Click del botón CmdCalendario.

El formulario Frm_Menu se descarga y la propiedad IsAddin pasa a False. Call


CargaCalendarioTrabajo llama al procedimiento de carga de hojas de calendario.

3. Creación de menús asociados al calendario en Excel


Vamos a modificar los procedimientos InsertarMenu y EliminarMenu del módulo
ModMenus para utilizarlas en el ámbito de los menús de gestión de calendario.

a. Modificación en InsertarMenu

El procedimiento ahora debe gestionar dos conjuntos de menús/submenús para ayudar a


la gestión de perfiles o de calendarios.

 Modifique el código como se muestra a continuación:


Existen elementos comunes como las llamadas a los procedimientos Menu_CargaMenu
o Menu_CerrarAplicacion.

Se han adjuntado los parámetros al procedimiento para identificar el entorno de trabajo


(StrTipoMenu) y el submenú específico a insertar (StrSubMenu) y la acción a asociar
(StrAccion).

La articulación del código es la misma que antes. El programa comprueba primero si el


menú ya está en Excel. A continuación se insertan el menú y los submenús.

No hay que olvidar de modificar o crear las dos llamadas al procedimiento


InsertarMenu en Frm_Menu.

 En el procedimiento CmdConsultaPerfiles_Click, hay que sustituir Call


InsertarMenu() por Call InsertarMenu("&Gestión de Perfiles", "&Subtotales por
profesiones", "Subtotales").
 En el procedimiento CmdCalendario_Click, inserte el siguiente código justo
antes de la llamada del procedimiento de carga de las hojas plantilla de
calendario:

b. Modificación en EliminarMenu

 Modifique el código como se muestra a continuación:

Sólo hay que insertar el menú Gestion de Calendarios a las instrucciones de


eliminaciones de menú en el bucle For-Each.

c. La eliminación de las hojas de plantillas de gestión de calendario

Si se cargan hojas para grabar un nuevo trabajo, debemos poder suprimirlas para poder
volver a hacer la misma operación más veces.
 Inserte el siguiente código en los procedimientos Workbook_BeforeClose del
módulo ThisWorkbook y Menu_CargaMenu del módulo ModMenus. En los dos
casos, el bloque de código se debe situar justo después de la instrucción que
elimina la hoja Subtotal por profesion.

El número total de hojas en la aplicación actualmente es 5, sólo hay que contarlas. El


procedimiento EliminarHoja se llama pasando por parámetro el nombre de la hoja a
eliminar. Sistemáticamente se selecciona la segunda hoja (Sheets(2).Name) ya que los
dos hojas a eliminar se han copiado justo detrás de la primera hoja (Inicio). Como sólo
hay 5 hojas en la aplicación, el programa sale del bucle.

Para el cierre de la aplicación por el submenú Salir de la aplicación del menú Gestión de
Perfiles, la gestión de la eliminación de la hojas se hace en el procedimiento
Menu_SalirAplicacion que es llamado por el submenú.

 Inserte el siguiente código en el procedimiento Menu_SalirAplicacion del


módulo ModMenus. El bloque se debe situar justo después de la instrucción que
suprime la hoja Subtotal por profesión.

 Ahora puede probar la carga de las hojas plantillas de gestión de calendario y los
menús asociados.
Gestión de las asignaciones y de las fechas de los trabajos
Ahora, el proceso de carga y de eliminación de las hojas para la creación de nuevos
trabajos está totalmente integrado en la navegación de la aplicación. Queda implementar
la asignación de candidatos a los nuevos trabajos y la gestión del calendario.

1. Las asignaciones a trabajos


Se trata de asignar uno o varios individuos a un trabajo. Ello va a depender del número
de tareas definidas con el cliente. Puede asignar una persona en el marco de una
sustitución en un servicio administrativo. Pero la necesidad puede también ser de un
sitio para el que haga falta un equipo con diferentes habilidades.

 Importe el formulario Frm_Gestion_Equipo en el IDE.


El formulario sólo contiene dos controles:

 Un ListBox que se llama Lst_Equipo. Todas las propiedades son las que tiene
por defecto el objeto cuando se crea.
 Un botón de comando que se llama Cmd_Salir.Su nombre visible es Salir
(Caption) y la propiedad Default está a True.

La ejecución del formulario se hace por medio del botón de comando Asignación de
individuos o Cmd_Gestion_Equipo de la hoja Asignación Trabajo.

a. Preparación de la lista y carga del ListBox

El código que hay en el procedimiento de evento UserForm_Initialize se ejecuta en el


momento de la carga del formulario. Este procedimiento actuará a varios niveles:

 en la hoja de trabajo Carga del ListBox


 en la hoja plantilla Asignación trabajo
 en el control Lst_Equipo

Vea el código que vamos a estudiar en detalle.


La tabla de la hoja Asignación trabajo se vacía cada vez que el usuario lanza el proceso
de selección de inscritos para proveer las necesidades de un trabajo. En esta tabla se
muestran los inscritos seleccionados. La celda D5 se pone a blancos. El número de
individuos seleccionados se muestra cuando se llena la tabla.

Para la carga del ListBox, se inserta una hoja de trabajo Carga del ListBox en el libro.
Préviamente, se inserta un filtro en la hoja Lista de inscritos para copiar sólo en la nueva
hoja de trabajo los individuos que tenga disponibilidad a SÍ (Field:=5, Criteria1:="Si").
Entonces se copian sólo las columnas de los apellidos, nombres y profesiones
(ActiveSheet.Columns("A:C").Copy).

A continuación hay que ordenar la lista copiada en la hoja Carga del ListBox. En lugar
de ejecutar el procedimiento OrdenarLista del módulo ModFormato, se utiliza el
siguiente código:

El método Sort permite ordenar el rango de celdas de datos que se adjunta. Las
instrucciones Key1 y Key2 recuperan el encabezado de las dos columnas sobre las que
se hace la ordenación.

El ListBox se puede alimentar ahora. Esta operación se hace sin utilizar la propiedad
List asociada a una tabla o el método AddItem insertado en un bucle.

La propiedad RowSource acepta rangos de celdas de hojas Excel. Devuelve el formato


exacto agrupando los datos en el mismo número de columnas introducido en origen.

b. Selección de los inscritos en el ListBox

El clic del usuario en un línea del ListBox selecciona en la tabla al individuo que se a
inscribir.

Vea el contenido del procedimiento de evento Lst_Equipo_Click que vamos a estudiar en


detalle.
El código del procedimiento empieza por comprobar que la selección del usuario no es
la primera fila (ListIndex = 0) correspondiente a los encabezados de las columnas del
ListBox. En este caso el programa sale del procedimiento.

Si la tabla de destino contiene al menos un individuo, un bucle Do While - Loop


muestra el conjunto de elementos y comprueba que la selección no esté ya presente. Si
es el caso, aparece un mensaje:

Si la selección no está en la tabla, se inserta. El apellido y el nombre se concatenan en la


primera columna de la tabla y la profesión en la segunda.

Como en una tabla de dos dimensiones, los datos se recuperan con dos índices que
empiezan en 0: el número de columna asociado al número de línea.
c. Cierre del formulario e inicialización de las hojas Asignación Trabajo y Calendario
Trabajo

El procedimiento de evento Cmd_Salir_Click del botón de comando Salir descarga el


formulario Frm_Gestion_Equipo y elimina la hoja de trabajo Carga del ListBox.

Pero es en el procedimiento de evento UserForm_Terminate que depende directamente


del cierre del formulario, donde se ubican las operaciones como dar formateo a la tabla
o la creación de lista de entrada para el calendario.
El código del procedimiento empieza por contar las asignaciones en la celda D5. Un
conjunto de condiciones anidadas comprueba primero la existencia o no de una
asignación en la tabla. La enumeración se concatena a continuación con la cadena de
caracteres "Asignación" en singular o plural. La segunda comprobación determina si se
trata de una asignación única o de varias asignaciones. A continuación se ordena la lista.

A continuación, se crean dos listas a partir de rangos de celdas.

La primera lista llamada Rango_Apellidos (Name:="Rango_Apellidos") agrupa todos


los apellidos y nombres utilizados en la tabla. Se hace referencia a esta lista a través del
nombre Rango_Apellidos .

El método Names.Add permite añadir la lista a la hoja activa. La propiedad


RefersToR1C1 transmite las coordenadas del rango de celdas utilizado.

La segunda lista llamada Rango_Profesiones está vinculada a la lista de profesiones


almacenada en la hoja Referencias: RefersToR1C1:= "=Referencias!R5C1:R" &
ActiveCell.Row & "C1".

Además, se trata la cuadrícula de la tabla a través de la llamada al procedimiento


CuadriculaRango.

2. La gestión del calendario de trabajo


Esta gestión abarca la inserción de las diferentes tareas del trabajo y la validación de
fechas introducidas por el usuario.

 Inserta en el IDE los tres módulos ModGestionFechas, ModGestionCalendario y


ModIntroduccionCalendario.
 Inserte en el módulo ModDeclaracion a continuación de las declaraciones de
variables existentes, el siguiente código.

a. La creación de nuevas tareas

La ejecución del procedimiento de creación de una nueva tarea en el calendario se hace


a través del botón de comando Insertar tareas o CmdInsertar de la hoja Calendario
trabajo.
Se llama al procedimiento InsertarTareas.

Antes de insertar una tarea, el programa comprueba que la tabla de asignaciones se ha llenado
correctamente y se ha introducido una fecha de inicio para la celda C7. Si no se cumple una de
las dos condiciones, se muestra unos de los siguientes mensajes y el programa sale del
procedimiento.
La fecha de actualización del documento se recupera en la celda C8 con la fórmula
=AHORA() en cada apertura del calendario.

El formato de introducción de la tarea se carga a partir de la hoja Referencias. Una vez


se ha copiado el rango de celdas, si no hay ninguna tarea, se inserta justo debajo de los
encabezados del calendario, sino se carga a continuación.

A continuación, se enumera la tarea y se informa en la celda G10 del calendario. El


número de tareas se recupera con la instrucción Range("B" & i).Value =
(ActiveCell.Row - 13) / 2. A continuación, se incrementa en cascada la fila siguiente y
el contador global.

En este momento sólo queda insertar las listas creadas al cerrar el formulario
Frm_Gestion_Equipo. Se inserta la lista de inscritos seleccionados Rango_Apellidos en
la columna Apellido y Nombre (Columna C). La lista de profesiones referenciadas
Rango_Profesiones se inserta en la columna Profesión (Columna D) del calendario.

La inserción se hace a través de una llamada al procedimiento InsertarLista. La


instrucción Call InsertarnLista("C", i, "=Rango_Apellidos") pasa por parámetro la
columna del calendario, el número de la fila donde se inserta la nueva tarea y el nombre
de la lista a cargar.
La propiedad Validation permite integrar un rango de datos. La instrucción Add
Type:=xlValidateList determina el tipo de validación que se inserta. Así, el rango de
datos cuyo nombre se recupera a través del parámetro StrRango (Formula1:=StrRango)
se insertará en forma de una lista desplegable.

La lista de profesiones puede parecer superflua ya que sólo se inserta la profesión


correspondiente a la elección del nombre en la tabla. Pero incluso si esa es la profesión
correspondiente que se muestra cuando el usuario ha escogido un individuo, puede
modificar la profesión por necesidades del trabajo y hacer evolucionar al colaborador
hacia una nueva actividad. Para él se trata de una evolución de su estado o de un
aumento de su habilidad en su rama profesional.

b. La gestión de las entradas

El procedimiento Gestion_Entrada del módulo ModIntroduccionCalendario agrupa


bloques de código que controlan las entradas del usuario en el calendario. A partir de
estos bloques de código, se efectúan numerosas llamadas a los procedimientos del
módulo ModGestionCalendario que dan formato al calendario.
Con el procedimiento de evento Worksheet_Change se recupera el contenido de las
celdas afectadas por esta entrada de datos. Este procedimiento se ejecuta en cada
entrada registrada en cualquier celda de la hoja Calendario Trabajo.

Durante la llamada al procedimiento, el valor se pasa a través de la variable Target


declarada como un objeto Range de donde se recuperan las diferentes propiedades y
métodos. El valor de la variable se pasa ByVal es decir por valor. Con esta declaración,
se fija el valor y si para validar su entrada el usuario ha hecho clic en otra celda, se
transmite el valor de la celda inicial. Con ByRef, la transmisión se hace por referencia
que es el tipo de paso por parámetro por defecto de VBA.

Vamos a ver los diferentes bloques de código que componen Gestion_Entrada.

 El primer bloque define la validez de las entradas de datos.


La introducción de las celdas C7 (Fecha de inicio del trabajo), C9 (Fecha inicio de visualización)
o de las fechas de inicio de tareas debe ser en formato fecha y no estar vacía (Not
IsDate(Target.Value) And Target.Value <> ""), en caso contrario se informa al usuario con un
mensaje de que la fecha no es válida.

Antes de salir del procedimiento, si la celda no está vacía antes de la entrada el valor inicial se
recarga con una llamada a la función EntradaOrigen. El código correspondiente es el siguiente:
Target.Value = EntradaOrigen(Target.Value).
Si existe un valor introducido por el usuario y pasado a través del parámetro
VarValorOrigen, se reenvía el valor original almacenado en VarValorOrigen a través de
la función y la variable Target se incrementa. Es posible que la celda esté vacía en
origen. En este caso, EntradaOrigen devuelve un valor vacío de tipo String: "".

Estas dos variables se declaran de tipo Variant ya que el dato introducido por el usuario
o el contenido original de la celda pueden ser de cualquier tipo.

La declaración de VarValorOrigen se hace en ModDeclaracion. Se alimenta en el


procedimiento de evento Worksheet_SelectionChange. Este procedimiento se ejecuta en
cada cambio de selección de celda en la hoja Asignación Trabajo.

Se desaconseja abusar de la declaración de variables de tipo Variant ya que


consumen mucho espacio en el sistema.

La validez de las entradas de datos se gestiona con el procedimiento Gestion_Entrada.


Si la entrada tiene un formato de fecha correcto, a continuación hay que comprobar que
no se trate de un sábado o un domingo. La función DatePart en la línea de código
DatePart("w", Target.Value, 2, 0) > 5, devuelve el número de día (parámetro W de
Target.Value). 2 necesita que el primer día de la semana sea el lunes (1 o domingo es el
valor por defecto). Si el valor devuelto es mayor que 5, se carga el valor inicial y el
programa sale del procedimiento.

La entrada de una fecha de inicio no puede ser inferior a la fecha de inicio del trabajo.
Se anula la entrada del usuario. El valor inicial se vuelve a cargar, un mensaje avisa al
usuario y el programa sale del procedimiento.
La fecha de inicio no puede ser superior a la fecha de inicio de cualquier tarea. Se anula la
entrada del usuario. El valor inicial se vuelve a cargar, un mensaje avisa al usuario y el
programa sale del procedimiento.

 El siguiente bloque de código implementa con una función integrada de Excel de tipo
ConsultaV la recuperación de la profesión del individuo cuando el usuario elige en la
lista desplegable.

El rango de celdas para buscar la profesión asociada corresponde a la tabla de la hoja


Asignación Trabajo. Para definir la línea máxima de este rango de búsqueda, sólo hay
que recuperar el contador de asignación: Asignación Trabajo’!B6:C" &
Left(Sheets("Asignación Trabajo").Range("D5").Value.

 La fecha de inicio de trabajo condiciona el formato de los encabezados de la


parte histograma del calendario.
En una modificación de la fecha de inicio del trabajo, el valor se informa en la fecha de inicio
de visualización.

Se llama al procedimiento InicializarCalendario del módulo ModGestionCalendario..


La zona de encabezado del histograma se informa a blancos. Si se ha alimentado la fecha de
inicio del trabajo, se recupera el número de semana con la línea de código DatePart("ww",
CDate(Range("C7").Value), 2, 0). Si el número es igual a 53, es la semana 1. Sino el número se
inserta en el encabezado.
El encabezado de los días trabajados y el número de días por semana se recuperan a
continuación con la llamada al procedimiento CargaNumDiasTrabajo del módulo
ModGestionCalendario.

El número de semana, la fecha de inicio de trabajo y el número de columna activo se


pasan por parámetro en la llamada al procedimiento: Call
CargaNumDiasTrabajo(ActiveCell.Value, Range("C7").Value, ActiveCell.Column).

Se hace visible la hoja de referencia Calendario. Se utiliza la función integrada Find de


Excel para hacer una búsqueda por fecha de inicio de trabajo (StrFecha) en la hoja
Calendario y en la columna Fecha (H). Cells.Find(What:=StrFecha, ... ).Activate.
Una vez se ha seleccionado la celda, es posible encontrar en la misma fila la
información, recuperarla y concatenarla en la celda destino de la hoja Calendario
Trabajo que se convierte en el título de los días trabajados (sólo se cogen los tres
primeros caracteres) y alimentar un contador J. Como el número de semana IntNumSem
es igual al de la columna D, se repite la operación en un bucle Do While - Loop
desplazando la selección de una celda hacia abajo: ActiveCell.Offset(1, 0).Select. La
propiedad Offset permite desplazar la selección en número de filas con el primer
argumento y en columnas con el segundo argumento. En este caso, el desplazamiento es
de una unidad hacia la fila siguiente. Sólo cuando se sale del bucle los títulos de los días
trabajados se concatenan con su contador (J) : Cells(11, Col).Value = Cells(11,
Col).Value & j.

Se preve la alimentación de los encabezados hasta el final del año en curso, como los
datos de la hoja Calendario.

 Es posible modificar la fecha de inicio de visualización. Esta manipulación


permite iniciar la visualización del histograma en función de la fecha elegida por
el usuario. Cuanto más alejadas en el tiempo están las tareas, más difícil es
consultar su informe en el histograma.
Un primer control impide la inserción de una fecha de inicio de visualización si la fecha de
inicio de trabajo está vacía. La fecha se elimina, un mensaje avisa al usuario y el programa sale
del procedimiento.

A continuación, el código comprueba que la fecha no sea inferior a la fecha de inicio del
trabajo. El valor inicial se vuelve a cargar, un mensaje avisa al usuario y el programa sale del
procedimiento.

Una vez pasa la validación, el programa muestra las columnas que han quedado ocultas:
Selection.EntireColumn.Hidden = False. Con un bucle For - Next se ocultan las columnas. El
contador del bucle se incrementa por la diferencia entre la fecha de inicio del trabajo y la fecha
de inicio de visualización: For i = 9 To DateDiff("WW", Range("C7").Value, Range("C9").Value) +
8. La función DateDiff devuelve la diferencia entre las dos fechas en semanas (WW).

 Los últimos bloques de código gestionan la introducción o eliminación de la


fecha de inicio de tarea así como el número de días asignados. De estos dos
datos depende el cálculo de la fecha de fin de tarea y también su informe en el
histograma.

En el caso de una eliminación de la fecha de inicio, se vacían las zonas de días


asignados y de la fecha de fin de tarea.

En una eliminación de los días asignados, se vacían las zonas de entrada de datos de
inicio de tarea y de fin de tarea.
La línea del histograma se vacía cada vez.

Para las entradas no nulas de fecha de inicio de tarea y de días asignados, se ejecuta el
procedimiento de cálculo de fecha de fin Gestion_Fechas del módulo ModGestionFechas. El
procedimiento de alimentación del histograma CalendarioTrabajo se ejecuta al mismo tiempo.

3. El cálculo de fechas y el informe en el histograma


Una vez se han validado las entradas del usuario, se ejecutan los cálculos de fechas. Las
fechas de fin darán lugar al informe de todo el resultado en el histograma.

a. La fecha de fin de tarea

La fecha de fin de tarea se calcula con la fecha de inicio como punto de inicio y el
número de días asignados como la duración.

 El procedimiento Gestion_Fechas se encarga de recuperar la fecha de inicio de


tarea y el número de días asignados para las diferentes tareas del calendario.
A partir de la fila 15 (k = 15), el programa analiza la hoja Calendario Trabajo con un
bucle Do While - Loop mientras haya tareas (Range("B" & k).Value <> "").

Si hay una fecha de inicio y un número de días asignados, estos datos se pasan por
parámetro al procedimiento Buscar_Fecha.

El procedimiento Buscar_Fecha se encarga de calcular e insertar la fecha de fin en el


calendario.
A partir de la función integrada de Excel Find, se recupera el estado del día de la hoja
Calendario. Mientras el número de semana sea igual al de la columna D y la variable del
número de días asignados (numDia) sea diferente de 0, el programa permanece en el
bucle Do While - Loop. Si no es un día festivo o un día de fin de semana, numDia se
decrementa a la vez que la fecha de inicio de tarea (Fecha_Ini) se incrementa un día:
Fecha_Ini = DateAdd("d", 1, Fecha_Ini). A continuación el programa pasa a la fila
siguiente del calendario (ActiveCell.Offset(1, 0).Select).

La fecha de fin en el calendario se alimenta después de la salida del bucle.


Ahora Gestion_Fechas va a ejecutar el procedimiento CalendarioTrabajo para informar
el resultado en el histograma teniendo en cuenta la fecha de inicio y la fecha de fin.

b. Elaboración del histograma

En la llamada al procedimiento CalendarioTrabajo se pasan por parámetro el número de


días asignados y la fecha de inicio de tarea. Las variables numDia y Fecha_Ini se
encargan de recuperar los datos.
Inicialmente se pone a blanco la fila de histograma que corresponde a la tarea, tanto el
contenido (Selection.ClearContents) como el color de fondo
(Selection.Interior.ColorIndex = xlNone).

Como máximo, el bucle Do While - Loop hará 53 pasadas antes de parar. Esto
corresponde al tamaño máximo del histograma de la columna I hasta AZ.

El proceso no comienza si el número de semana de la primera celda del encabezado es


igual al de Fecha_Ini (Cells(13, i).Value = DatePart("ww", Fecha_Ini, 2, 0)). Se
identifica la columna y se selecciona la celda a tratar. Si no es el caso, se incrementa la
variable i y el bucle se vuelve a ejecutar hasta que coincida el número de semana.

El fondo de la celda a tratar se colorea en rojo. El programa muestra la hoja Calendario


para buscar la correspondencia de Fecha_Ini en la columna Fecha.

Ahora hay que entrar en un nuevo bucle Do While - Loop anidado en el primero.
Mientras el número de semana corresponda, si el día seleccionado en la hoja no es
festivo o de fin de semana, la celda de del calendario se incrementa en una unidad por
día trabajado. Por el contrario, el número de días asignados se disminuye en una unidad
(numDia = numDia - 1) y si es igual a 0, el programa sale del bucle.

En cada pasada en este bucle, se incrementa la variable j en una unidad y entonces se


trata la siguiente fila de la hoja Calendario: es decir, la siguiente fecha
(ActiveCell.Offset(1, 0).Select).

Una vez se ha salido de este segundo bucle anidado, si numDia es igual a 0, se sale del
primer bucle y del procedimiento. El programa pasa a la fila siguiente de la hoja
Calendario. La variable Fecha_Ini se alimenta con el número de días pasados,
trabajados o no (variable j): Fecha_Ini = DateAdd("d", j, Fecha_Ini).

 Puede probar la aplicación.

4. Guardar el trabajo
Cada calendario creado es un nuevo trabajo que hay que guardar. Esto requiere una
copia de la hoja plantilla Calendario Trabajo sin copiar el código VBA que contiene la
hoja.
El menú Grabar el trabajo llama al procedimiento GuardarTrabajo del módulo
ModGestionCalendario.

Vea el código del procedimiento para guardar:


El procedimiento se inicia con la instrucción de captura de errores que envía a la etiqueta
TratarError: al final del código. Si el número del error capturado es 6, un mensaje informa al
usuario del número de error y de que el trabajo no se ha guardado.

El programa controla si el nombre del trabajo y su fecha de inicio se han alimentado


correctamente. Si falta alguno de los datos, se informa al usuario con un mensaje y el
programa sale del procedimiento.

La variable StrRuta se alimenta con la ruta donde se va a guardar el trabajo (StrRuta =


"C:\Formacion VBA Excel 2010\Trabajos\" & Range("B4").Value & "\"). El directorio
Trabajos contiene otro directorio que se llama como el cliente del trabajo. Todos los
trabajos relacionados con este cliente se guardarán en este directorio.

La variable StrNomFic recupera el nombre de archivo a guardar que es la concatenación


del nombre del trabajo en el calendario con la fecha de inicio del trabajo con el formato
yyyymmdd (StrNomFic = Range("B4").Value & " " & Format(Range("C7").Value,
"yyyymmdd") & ".xls").

Se valida la existencia del directorio destino, así como la existencia del archivo a
guardar.
A continuación, el programa inserta una nueva hoja de trabajo en el libro llamado
Trabajo. Se copia el contenido de la hoja Calendario Trabajo sin el código VBA
vinculado a esta hoja (sólo los valores y el formato).

Se ajusta el zoom de la hoja Trabajo igual que la hoja Calendario Trabajo


(ActiveWindow.Zoom = 75).

Por último, la hoja Trabajo se mueve a un nuevo libro y este último se graba con las
variables StrRuta y StrNomFic.

A continuación se cierra el nuevo libro sin grabar las modificaciones. Si todo va bien y no se
captura ningún error, se envía un mensaje al usuario comunicándole que el archivo se ha
guardado correctamente.

El procedimiento Menu_CargaMenu del módulo ModMenu recarga el formulario Frm_Menu.

Gestión de la aplicación con una base de datos


Objetivos
La hoja Excel puede servir en cierta medida de contenedor con el fin de almacenar
datos. Es posible utilizarla como una base de datos. Pero en términos de accesibilidad,
de volumen o de seguridad, las hojas Excel no pueden competir con una base de datos
como Access. Esta herramienta forma parte del paquete distribuido por Office 2010.

Hay que establecer una conexión desde Excel a la Base De Datos (BDD) para tener
acceso a los datos que contiene. Es entonces cuando es posible consultar, crear, eliminar
o modificar los datos de esta base de datos. Por medio de los comandos del lenguaje
Visual Basic Application que también soporta Access vamos a poder utilizar otro
lenguaje dedicado al tratamiento de datos, llamado SQL (Structured Query Language).

En este capítulo, vamos a ver como gestionar datos como la lista de inscritos, las fechas
del calendario o la lista de las diferentes profesiones definidas en la agencia de trabajo
temporal.
Haremos una presentación rápida del lenguaje SQL y de la base de datos Access.
Veremos también como utilizar cuadros de diálogo para encontrar y grabar las rutas de
acceso a los archivos destino en el árbol de directorios del sistema operativo. Entonces,
podremos estudiar la base de datos y lanzar consultas SQL con VBA para manipular los
datos.

La base de datos BDD_Agencia y su entorno


En el ámbito de nuestra aplicación, vamos a utilizar la versión 2010 de Access. Puesto
que el núcleo de este libro no son las bases de datos relacionales, hablaremos sin entrar
en detalles de los diferentes intercambios entre la aplicación Gestión de perfiles y la
base de datos y de los procesos que se añadirán.

1. Descargue de la web del editor el fichero BDD_Agencia.accdb. Sitúelo en el


directorio Formacion VBA Excel 2010, con la siguiente ruta: C:\Formation
VBA Excel 2010\BDD_Agencia.accdb.

La base de datos BDD_Agencia.accdb es una herramienta contenedor que nos va a


permitir almacenar los datos necesarios para el funcionamiento del programa. Hasta
ahora los datos estaban insertados en las hojas de trabajo. Estas hojas en primer lugar
tienen la desventaja de sobredimensionar el libro. Además, incluso si están ocultas, no
están realmente protegidas, ya que una vez que el usuario ha hecho una elección en el
formulario, la propiedad IsAddin pasa a False y puede acceder a las hojas del libro. En
ese momento, nada impide visualizar una hoja oculta para realizar modificaciones. Si
los datos se cargan a partir de la base de datos, las posibles modificaciones no afectan al
origen y la información necesaria para el buen funcionamiento de la aplicación
permanece intacta, este es el principio aplicado a través de plantillas cargadas a partir de
una copia original.

Esto no significa que no se puedan hacer cambios en los datos. Si tomamos el ejemplo
del estado de los miembros de la agencia, su disponibilidad evoluciona con las
asignaciones a trabajos. Esta evolución se debe poder informar en cada cambio de
estado en la base de datos.

Una vez gestionada en una base de datos, la información está disponible para otras
aplicaciones desarrolladas en VBA Excel, en otra herramienta de Office o en otro
lenguaje de programación. Lo esencial es poder establecer una conexión a la base de
datos Access BDD_Agencia. Todas las operaciones como la creación, la eliminación o
la modificación de datos son visibles después de la validación por el conjunto de
aplicaciones conectadas a la base.

1. Las tablas
Todos los datos contenidos en las hojas del libro Excel se han introducido en la tablas
Tab_Calendario y Tab_Inscritos. Lo mismo ocurre para algunos datos de la hoja
Referencias (es importante no eliminarla). La información del nombre de usuario y la
contraseña se gestionan ahora en la tabla Tab_Usuarios. La lista de profesiones de los
miembros de la agencia se almacena en la tabla Tab_Profesiones. En la siguiente
ilustración se representan las diferentes tablas de la base de datos BDD_Agencia y sus
diferentes campos.

En Access, las tablas son objetos en los que se agrupa la información. Si tomamos como
ejemplo la tabla Tab_Calendario, los encabezados de la columnas son ahora los encabezados
en los campos.

En el caso de la tablaTab_Inscritos, se han añadido campos suplementarios para tratar nuevos


datos que vamos a guardar al crear y guardar un trabajo.

De este modo, los campos FECHA_INICIO, FECHA_FIN se informarán con la fecha


de inicio y de fin de la tarea a la que se le ha asignado. El nombre del cliente para el que
realiza el trabajo se graba en el campo CLIENTE.

En la tabla Tab_Usuarios, tenemos los nombres y contraseñas asociados para conectarse


a la aplicación en el formulario de identificación. En el siguiente capítulo se explicará el
campo Permisos_Usuario. Ahora puede crear una contraseña y un nombre asociado por
usuario.
La tabla Tab_Profesiones enumera la lista de profesiones igual que la lista de la hoja
Referencias.

2. La conexión a la base de datos BDD_Agencia


Antes de poder manipular los datos de la base, hay que establecer una conexión a
Access desde Excel. Para establecer esta conexión, tenemos que utilizar propiedades y
declarar nuevos objetos.

a. Añadir nuevas referencias

 Inserte el siguiente código en el módulo ModDeclaracion.

De momento, el programa no reconoce estas propiedades. En el momento de la compilación


del código VBA el programa le muestra el siguiente mensaje:
Para arreglarlo, hay que hacer referencia a estas propiedades para que los tipos de
variables ADODB.Connection o ADODB.Recordset se pueden definir.

 Con el menú Herramientas - Referencias del IDE, abra el cuadro de diálogo


Referencias - VBAProject.

 En la lista Referencias disponibles, marque Microsoft ActiveX Data Objects 6.0


Library. Valide y cierre este cuadro haciendo clic en el botón Aceptar. Esta
referencia le va a permitir establecer una conexión de tipo ADO (ActiveX Data
Objects) con la base de datos.

b. Recuperación de la ruta de la base de datos

 Inserte el título Ruta BDD en la celda C4 de la hoja Referencias y la ruta


C:\Formacion VBA Excel 2010\BDD_Agencia.accdb en la celda D4.
 Inserte el módulo ModBDD.

La mayor parte de las operaciones relativas a los intercambios con la base de datos se
agrupan en este módulo.

 Inserte en el procedimiento de evento CmdValidacionUsuario_Click del


formulario Frm_Identificacion y justo después del control de las entradas de
usuario, el siguiente código:

En el momento de la identificación del usuario es necesario establecer la conexión con


la base de datos.

Ahora podemos comenzar a estudiar el procedimiento CnxDB.

El procedimiento comienza recuperando la ruta de la base de datos. Esto se consigue con una
llamada al procedimiento CargaRutaBDD del módulo ModBDD.
Por defecto, la ruta de la base de datos se almacena en la hoja Referencias del libro. El
proceso que establece la conexión se ejecuta en el formulario de identificación
Frm_Identificacion, lo que justifica deshabilitar la propiedad IsAddin en el acceso a la
hoja Referencias que está oculta. La variable StrRuta se carga con la ruta de la base de
datos recuperada.

El proceso de creación de la conexión continúa en el procedimiento CnxDB. Se


comprueba la ruta de la base de datos. No se trata de comprobar la existencia de
directorios o la presencia de un archivo con nombre igual al que el programa quiere
grabar, pero sí de definir si la base de datos sigue en el lugar correcto.

Hasta ahora, nos hemos conformado con tener la ruta de los ficheros a leer o guardar en
el código. Esta solución no es nada flexible ya que en caso de modificación del entorno
de trabajo, hay que modificar el código para modificar la ruta. Pero vamos a
implementar otra solución más dinámica con los cuadros de diálogo.

Si la ruta no corresponde a ningún archivo, se muestra un mensaje al usuario.

El usuario puede escoger cancelar (IntRes = 2) y la aplicación se cierra sin guardar los
datos. Si por contra escoge reintentar (IntRes = 4), el programa llama al procedimiento
RutaBDD del módulo ModBDD.

c. El cuadro de diálogo Examinar

Vamos a utilizar un cuadro de diálogo llamado Examinar que va a permitir navegar en


al árbol de directorios a fin de encontrar el fichero BDD_Agencia.accdb y recuperar la
ruta de acceso.
La propiedad FileDialog permite activar un cuadro de diálogo. El tipo del cuadro de diálogo se
pasa por parámetro: msoFileDialogFilePicker define un cuadro que da la posibilidad al usuario
de seleccionar un fichero.
Un filtro delimita la selección del usuario. Sólo los ficheros que tengan la extensión
.accdb son visibles en los directorios abiertos en el cuadro de diálogo (Filters.Add "Elija
base de datos", "*.accdb"). El directorio abierto por defecto en el cuadro es el directorio
de la aplicación Gestión de Perfiles (InitialFileName = ThisWorkbook.Path). Se limita
la selección del usuario a un solo fichero (AllowMultiSelect = False).

En esta fase del procedimiento, el programa comprueba si el usuario ha hecho clic en el


botón Cancelar. Si es así, la condición If .Show = -1 Then lleva al siguiente Else y el
programa sale del procedimiento.

Si el usuario no ha cancelado, un bucle de tipo For - Each revisa la selección de este


último (un fichero Access en nuestro caso). La variable VarRuta de tipo Variant
recupera la ruta del archivo seleccionado (For Each VarRuta In .SelectedItems). A
continuación de la desactivación de la propiedad IsAddin y la visualización de la hoja
Referencias, se cambia la ruta en la celda D4 de esta hoja
(Sheets("Referencias").Range("D4").Value = VarRuta). La variable StrRuta se alimenta
del mismo modo. Se graba la modificación (ThisWorkbook.Save) y un mensaje informa
al usuario que la ruta se ha modificado correctamente en la hoja Referencias.

Después de haber analizado los procedimientos CargaRutaBDD y RutaBDD, volvamos otra vez
al procedimiento CnxDB.

En la arquitectura del código, es preferible evitar anidar demasiado las llamadas


de procedimientos o de funciones que vuelven ellos mismos a otras llamadas. Si
se vuelve a releer el programa, es muy difícil seguir el desarrollo del código sin
perder de vista la lógica de su organización.

d. Apertura de la conexión a la base de datos

Una vez se ha recuperado y validado la ruta de la base de datos, podemos establecer la


conexión.

La instrucción Set da a CnxBDD una referencia al objeto Connection, lo que le permite


recuperar todas sus propiedades y métodos (Set CnxBDD = New ADODB.Connection).

La propiedad ConnectionString recupera la ruta de la base de datos de la variable


StrRuta que se concatena para que el programa la identifique como variable de tipo
String y se inserta en una cadena de caracteres ConnectionString
("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & StrRuta & ";Persist Security
Info=False;Jet OLEDB:Database").

La conexión se abre: Open StrRuta.


e. Cierre de la conexión a la base de datos

Si la conexión está abierta, hay que cerrarla para no dejar que los procesos consuman
inútilmente recursos del sistema.

 Inserte la siguiente instrucción al final del procedimiento


Workbook_BeforeClose del módulo ThisWorkbook justo antes de guardar el
libro (ThisWorkbook.Save).

En el momento del cierre del libro se llama al procedimiento FinCNX.

Antes de intentar cerrar la conexión, hay que comprobar que está activa con la función
IsEmpty que comprueba si el objeto CnxBDD está inicializado correctamente. En el
caso en que el usuario decida salir de la aplicación antes de conectarse o si no se llega a
identificar, en el cierre del libro (procedimiento Workbook_BeforeClose) se ejecuta de
todos modos el procedimiento FinCNX.

Si el objeto CnxBDD está correctamente inicializado, se cierra (Close) y después se


elimina su referencia (Nothing). Lo mismo ocurre con el objeto RstBDD que
corresponde a un RecordSet que estudiaremos un poco más tarde en este capítulo.

 Puede probar la aplicación. La conexión se hace sin afectar al desarrollo del


programa.
 Mueva ahora el fichero BDD_Agencia.accdb a un nuevo directorio llamado
Base de datos en el directorio Formacion VBA Excel 2010. Si ejecuta ahora la
aplicación, justo después de haber validado el nombre y la contraseña, un
mensaje le indica que la ruta no es válida. Por medio de nuevas funcionalidades
hay que grabar la nueva ruta de acceso como: C:\Formacion VBA Excel
2010\Base de datos\ BDD_Agencia.accdb.

f. El formulario de cambio de base de datos

Si el programa ha comprobado y validado la ruta en la identificación del usuario, éste


último debe tener la posibilidad de cambiar de base de datos a lo largo del uso de la
aplicación.

 Añada un botón suplementario en Frm_Menu al que le dará como nombre


visible Seleccionar base de datos y CmdRutaBDD como nombre real para el
programa.
 Inserte el siguiente procedimiento de evento:

El procedimiento CmdRutaBDD_Click descarga Frm_Menu y carga Frm_Ruta_BDD.

 Importe el formulario Frm_Ruta_BDD.

El aspecto de este formulario es bastante sencillo. Muestra un TextBox que tiene como
nombre real TxtRutaBDD. Este TextBox de entrada y salida es suficientemente largo
para contener una ruta de base datos.
El botón que sólo tiene tres puntos (...) tiene como nombre real CmdOrigenBDD.

Por último un botón Salir permite cerrar el formulario.

Ahora vamos a estudiar el código asociado a este formulario.

Este formulario no hace más que repetir las funcionalidades presentadas en los párrafos
anteriores.

En la carga del formulario, la llamada al procedimiento CargaRutaBDD recupera la ruta


grabada en la hoja Referencias. A continuación se carga en TxtRutaBDD por medio de
la variable StrRuta.

El procedimiento de evento CmdOrigenBDD_Click ejecuta el cuadro de diálogo con


una llamada al procedimiento RutaBDD. La ruta recuperada se carga en TxtRutaBDD.

Se cierra la conexión a la base de datos (Call FinCNX) para a continuación volver a


ejecutarla para apuntar al nuevo emplazamiento seleccionado (Call CnxDB).

Puede probar esta funcionalidad para que la aplicación apunte a la base de datos
BDD_Agencia.accdb del nuevo directorio Base de datos.

3. El lenguaje SQL
Este es un lenguaje de consulta de base de datos relacionales. Existen instrucciones para
seleccionar, eliminar, inserter o actualizar registros en la base de datos. Vamos a
comenzar por mostrar los principales comandos susceptibles de utilizarse en la
aplicación Gestión de Perfiles.

Existen muchos otros comandos que no mencionaremos ya que no es el objetivo de este


libro.

a. Los principales comandos SQL

 Los comandos:
b. La elaboración de la consulta SQL

Para ilustrar nuestro ejemplo, vamos a utilizar una tabla ficticia llamada Tab_Clientes
que contiene diversos campos como Apellidos, Nombre, Edad, Dirección, Población,
Código Postal, País, Teléfono... Estos campos agrupan todos lo datos relacionados con
los clientes.

La selección de registros
SELECT * FROM Tab_Clientes.

Esta consulta devuelve por defecto todos los datos de todos los campos de la tabla
Clientes. El carácter * indica que se seleccionan todos los campos después del SELECT.
No hay condición(es) y se seleccionan todos los clientes.

SELECT Apellidos, Nombre, Edad, Poblacion FROM Tab_Clientes WHERE Edad


> 25 AND
Pais = ’España’.

En esta segunda consulta, sólo se devolverán los valores de los campos indicados.
Además, se seleccionarán sólo los clientes de la tabla Tab_Clientes que tengan más de
25 años y vivan en España. Este último criterio de la condición no forma parte de los
campos devueltos por la consulta. En el código SQL, todos los datos de tipo
alfanumérico van entre comillas simples (’España’). Las fechas van entre almohadillas
(#01/10/2010#) y sólo los datos de tipo numérico no se enmarcan con ningún otro
elemento.

Pero en el lenguaje Visual Basic y en VBA, la comilla simple se utiliza para


comentar código que ya no se utiliza o escribir texto relativo al desarrollo en
curso. Como veremos un poco más tarde sustituiremos las comillas simples por
comillas dobles.

SELECT Apellidos, Nombre, Edad, Poblacion FROM Tab_Clientes; WHERE


Edad > 25 Asc
ORDER BY Apellidos, Nombre.

Esta consulta es idéntica a la segunda pero además está ordenada por los apellidos y el
nombre del cliente. Por defecto, la clasificación es ascendente (ASC). Para que sea
descendente, hay que incluir la sentencia DESC.

La eliminación de registros
DELETE FROM Tab_Clientes WHERE CONDICION.

Con esta consulta, se eliminan registros de una tabla. Pero hay que indicar una
condición poque sino se eliminan todos los registros de la tabla.

DELETE FROM Tab_Clientes WHERE Poblacion = ’Barcelona’.

Sólo se eliminan los clientes que vivan en Barcelona.

La inserción de registros
INSERT INTO Tab_Clientes VALUES (Campo1, Campo2, Campo3 ...).

Esta sentencia permite añadir un registro a una tabla.

En caso de no llenar todos los campos, se utiliza este formato.

INSERT INTO Tab_Clientes VALUES (Apellidos, Nombre, Edad,Poblacion)


VALUES
(’PARDO’, ’David’, 43, ’Girona’).

La modificación y actualización de registros


UPDATE Tab_Clientes SET Campo1 = Valor WHERE CONDICION.

Con esta sentencia, se modifica el Campo1 de todos los registros de la tabla. Igual que
en la eliminación, hay que indicar una condición si no quiere actualizar todos los
registros de la tabla.

UPDATE Tab_Clientes SET Edad = 42 WHERE Apellidos = ’PARDO’ AND Nombre


=
’David’.

Para una mejor legibilidad del código, es aconsejable poner todas las sentencias
SQL en mayúsculas.

Para dar más facilidades, la base de datos Access tiene una herramienta gráfica
integrada de creación de consultas con un generador de SQL. Esto permite
probar la consulta una vez que está construida para validar el resultado y
sobretodo para recuperar el código SQL e integrarlo en el código de la aplicación
en desarrollo.

4. El flujo de datos con la base de datos


Vamos a utilizar nuestra conexión y descubrir todas las posibilidades para Gestión de
Perfiles de esta nueva funcionalidad. Cada consulta de la aplicación a los registros de la
base de datos envía una consulta SQL que traduce en lenguaje estructurado la
descripción precisa de la petición.

a. El objeto Recordset

En el procedimiento ConsultaBDD del módulo ModBDD se envía la consulta a la base


de datos.

La consulta se recupera en los parámetros del procedimiento (ConsultaSQL).

La instrucción Set asigna a RstBDD una referencia al objeto Recordset que le permite
recuperar todas las propiedades y métodos (Set RstBDD = New ADODB.Recordset).
RstBDD se asocia a la conexión activa a la base de datos (RstBDD.ActiveConnection =
CnxBDD) y se transmite la consulta (RstBDD.Open (RequeteSQL)).

b. La identificación de los usuarios en la base de datos

La primera consulta a ejecutar se refiere a la identificación de los usuarios.

Vamos a realizar algunas modificaciones en el código del procedimiento de evento


CmdValidacionUsuario_Click del formulario Frm_Identificacion.

 Inserte el siguiente código justo después de la llamada a la conexión Call


CnxDB.
A continuación, comente el código que inicialmente le permitía recuperar el nombre y la
contraseña de la hoja Referencias.

Para autentificar la entrada del usuario en su petición de identificación, hay que acceder
a la tabla Tab_Usuarios. La conexión a la base se ha activado por medio de la
instrucción Call CnxDB. Tenemos que construir la consulta SQL adecuada y cargarla en
la variable de tipo String StrSQL.

Vamos a ver en detalle los componentes de esta consulta:


El objetivo es saber si el nombre y la contraseña introducidos por el usuario existen en
la base de datos. Los campos a devolver (SELECT) son Pass_Usuario y
Nombre_Usuario de la tabla Tab_Usuarios (FROM). Basta con apuntar con la
condición (WHERE) al registro buscado. Para ello, hay que integrar el contenido de los
TextBox TxtNombreUsuario y TxtPass. Lo más difícil es concatenar en una cadena de
tipo alfanumérico los objetos del código y hacer que se reconozcan como tales para
aprovechar sus propiedades. En el ejemplo, la propiedad Value permite recuperar su
contenido.

La función Trim permite suprimir los espacios que se hayan podido dejar en la
introducción y la función UCase convierte el texto en mayúsculas.

El objeto a concatenar se enmarca del siguiente modo: " & Objet & ". Las dobles
comillas permiten cerrar la cadena SQL pero como en nuestro caso se trata de datos de
tipo alfanumérico, debemos añadir las comillas simples: ’" &
UCase(Trim(TxtNombreUsuario.Value)) & "’.

La consulta que se ha construido se almacena en StrSQL y se envía al procedimiento


ConsultaBDD (Call ConsultaBDD(StrSQL)). El objeto RstBDD devuleve si la entrada
del usuario corresponde con algún registro que devuelve la consulta. Esto es lo que se
comprueba en la línea de código If RstBDD.EOF Then. El método EOF (End of File)
indica la posición fin del archivo, lo que significa que no se ha encontrado ninguna
correspondencia en la tabla. Esta comprobación de tipo booleano devuelve el valor
True. La entrada no es válida. El programa sale del procedimiento habiendo
previamente puesto a blancos los TextBox y advertido al usuario con un mensaje.

Se cierra (RstBDD.Close) el Recordset ya que es inútil dejar procesos que consuman


recursos en el sistema. Lo mismo ocurre en el caso de que la identificación sea válida y
que el valor devuelto por la comprobación sea False.

Antes de descargar el formulario Frm_Identificacion y de cargar el formulario


Frm_Menu, se ejecuta el proceso de recuperación de los datos de la base de datos para
alimentar la lista de profesiones, el calendario y la lista de inscritos.

 Puede probar la aplicación y la identificación de usuario.

La gestión de los datos de la agencia


Esta gestión se basa en la creación y la carga de las hojas de trabajo Calendario y Lista
de Inscritos a partir de la base de datos ya que estas hojas hasta ahora ocultas se van a
eliminar. Además, ello implica también guardar las modificaciones o nuevos registros
en la base de datos.

 Puede eliminar las hojas ocultas Calendario y Lista de Inscritos. Pero también
hay que modificar los tres procedimientos de evento Workbook_BeforeClose del
módulo ThisWorkbook, Menu_CerrarAplicacion del módulo ModMenus y
CmdSalirMenu_Click del formulario Frm_Menu. En el bloque de código que
gestiona la eliminación de las hojas de trabajo, el número de hojas totales por
defecto de la aplicación pasa de 5 a 3 (método Count) como se muestra en las
siguientes líneas:

 Aplique modificaciones similares en el procedimiento Menu_CerrarAplicacion. El


número de hojas por defecto se modifica de 5 a 3.

Las hojas Calendario y Lista de Inscritos que se crean y alimentan a partir de la base de
datos se suprimirán después de utilización igual que las hojas Calendario Trabajo y
Asignación Trabajo.

1. La alimentación de las hojas de trabajo


Las hojas de trabajo Calendario y Listas de Inscritos se van a explotar de forma
dinámica cargándose en el inicio del programa justo después de la identificación del
usuario. Todas estas operaciones iniciadas a partir de llamadas a procedimientos que
están almacenados en el módulo ModDataBDD.

 Inserte el módulo ModDataBDD.

a. La carga de las profesiones de la agencia de trabajo temporal

La llamada al procedimiento CargaProfesionesBDD ejecuta la carga de las profesiones


de la agencia.
La lista de las profesiones almacenadas en la tabla Tab_Profesiones se tiene que situar
en el mismo sitio que ocupaba hasta ahora en la hoja Referencias. Cuando la propiedad
IsAddin pasa a False y la hoja es visible, el programa limpia la lista grabada durante la
última conexión.

La consulta SQL sólo devuelve el campo Profesiones. Dado que no se ha indicado


ninguna condición (WHERE), en el juego de registros se incluyen todos los registros de
la tabla Tab_Profesiones. La única particularidad de esta consulta es que está ordenada
ascendentemente (por defecto cuando no se indica nada) con la instrucción Order By del
campo Profesiones.

Después de la llamada al procedimiento ConsultaBDD, la consulta se transfiere a la


base de datos y el Recordset RstBDD recupera el juego de registros. Ahora basta con
restituir los datos en la hoja Referencias. Para ello, basta con recorrer el juego de
registros hasta el último y cargarlo en la hoja.

Se ha sumado 5 a la variable i, que es el número de la fila de inicio de la lista en la hoja.


En un bucle de tipo Do While - Loop, en la celda de la columna A en la línea
correspondiente al contador i se carga el valor devuelto por la consulta para el campo
Profesiones: Sheets("Referencias").Range("A" & i).Value = RstBDD("Profesiones").
Después de cada carga, no hay que olvidar incrementar el contador i en una unidad para
pasar a la fila siguiente de la hoja. La instrucción RstBDD.MoveNext permite pasar al
registro siguiente en el Recordset. Esto permite evitar un problema de bucle infinito
dado que la condición de salida del bucle se hace con el fin del juego de registros y que
esto último no ocurrirá nunca. La secuencia continúa hasta que se alcanza el último
registro del Recordset (Do While Not RstBDD.EOF). Una vez fuera del bucle, se cierra
el Recordset (RstBDD.Close) que vuelve a estar disponible para una nueva consulta a la
base de datos BDD_Agencia.

Como para todos los bucles infinitos, la combinación de teclas [Ctrl][Pause]


queda como último recurso para salir del Recordset.

La hoja Referencias se oculta nuevamente y la propiedad IsAddin se pone a True.

b. La carga del calendario

La llamada al procedimiento CargaCalendarioBDD del módulo ModDataBDD ejecuta


el proceso de carga del Calendario.
Esta vez la carga del calendario a partir de la base necesita la creación de la hoja Calendario.
Después de haber modificado la propiedad IsAddin a False, el programa inserta una nueva hoja
llamada Calendario justo después de la hoja Inicio. Los encabezados de columnas (de la A a la
H) se cargan en la primera fila de la hoja para los 8 campos de la consulta. Por otra parte, se
utiliza el signo * para devolver por defecto todos los campos de la tabla Tab_Calendario. Se
ordena por el campo FechaDia.
Después de la carga del Recordset por el procedimiento ConsultaBDD, éste último se
inserta de nuevo en un bucle Do While - Loop. Mientras que no se alcance el último
registro de RstBDD, cada uno de los diferentes valores de los diferentes campos de la
consulta se carga en las columnas correspondientes de la hoja Calendario antes de pasar
a la fila siguiente y al registro siguiente del Recordset. En la instrucción
Sheets("Calendario").Range("A" & i).Value = RstBDD!Año, el valor del campo Año se
carga en la columna A y en la fila seleccionada por el contador i. Esta instrucción se
repite en el bucle tantas veces como campos haya en la consulta SQL. En la carga de las
profesiones, la instrucción que recupera el valor del campo era similar a esta:
RstBDD("Profesiones"). Las dos formas son válidas.

A continuación, se cierra el objeto RstBDD. A la columna H que contiene la fecha del


día del calendario se le da el formato "d/m/yyyy". Sin esta instrucción, veríamos el valor
40182 en lugar de 04/01/2010.

La hoja Calendario se oculta y la propiedad IsAddin se pone a True.

c. La carga de la lista de inscritos

La llamada al procedimiento CargaInscritosBDD del módulo ModDataBDD ejecuta el


proceso de carga de la lista de inscritos.
Las acciones son idénticas a las del procedimiento de carga del calendario. La hoja Lista de
inscritos se crea justo después de la hoja Inicio. Se cargan los encabezados de columnas (de la
A a la E) en la primera fila para los 5 campos de la tabla Tab_Inscritos de la consulta. Se ordena
por los campos APELLIDOS y NOMBRE.

La recuperación de los datos enviados por el Recordset se hace de nuevo con un bucle Do
While - Loop y comprobando el fin de archivo EOF. Una vez que se han cargado todos los
inscritos de la agencia en la hoja, se cierra el objeto RstBDD.
Se oculta la hoja Lista de inscritos y se pone la propiedad IsAddin a True.

2. Las consultas de actualización


Todos los datos necesarios para el funcionamiento de la aplicación se han almacenado
en la base de datos y se cargan en el momento oportuno. Pero estos datos no son fijos y
pueden evolucionar cuando se crea un trabajo o cuando se modifica el estado de los
miembros de la agencia. Pero antes de gestionar los cambios en la base de datos, vamos
a estudiar un función muy útil.

a. La gestión de los apóstrofos y el lenguaje SQL

 Inserte una nueva función llamada Apostrofo en el módulo ModBDD.

Como hemos visto anteriormente, existen comillas simples en las cadenas de caracteres
SQL para delimitar valores de tipo alfanumérico. Pero pueden existir comillas simples
en forma de apóstrofos dentro de las cadenas de caracteres que componen los valores
que se soportan por las consultas SQL. Es por ejemplo el caso del apellido DE L’HORT
en la lista de inscritos. Pero en el lenguaje Visual Basic y en VBA, la comilla simple se
utiliza para comentar código obsoleto o texto relativo al desarrollo en curso.

Para solucionar esto, la función Apostrofo se utiliza para recuperar con un bucle For -
Next la cadena de caracteres y buscar si hay alguna comilla simple para duplicarla
(Apostrofo = Apostrofo & Mid(StrCadena, i, 1) & "’"). A pesar de esto, sólo se grabará
una comilla en la base de datos. Puede probar esta función grabando un trabajo con un
nombre de cliente que tenga una o varias comillas.

b. La modificación del estado de un miembro

Esta modificación se refleja en la hoja Lista de inscritos. Pero esto no es suficiente ya


que si modifica la disponibilidad a NO, se perderá la modificación ya que cuando se
cierra la aplicación se elimina la hoja Lista de inscritos.

El procedimiento de evento CmdValidacionMiembro_Click del formulario


Frm_Miembros al mismo tiempo que actualiza la hoja de trabajo, debe lanzar una
consulta de actualización de los datos modificados en la tabla Tab_Inscritos de la base
de datos.

 Inserte las siguientes líneas de código en CmdValidacionMiembro_Click a nivel


de bloque de código dónde el usuario confirma la grabación de las
modificaciones y actualiza la hoja Lista de inscritos. Este bloque acaba con las
líneas de código Sheets("Lista de inscritos").Range("E" &
LstMiembros.ListIndex + 2).Value = "No" y End If.
La consulta que va a alimentar la variable StrSQL tiene la particularidad de ser una
cadena con una inserción de caracteres condicional. A continuación de los comandos
UPDATE y SET, los campos PROFESION, NIVEL y DISPONIBILIDAD se alimentan
a partir de los controles correspondientes de Frm_Miembros.

En este punto, la aplicación comprueba si la disponibilidad está a Sí (If


OptDispoSi.Value Then). Conviene recordar que los tres campos FECHA_INICIO,
FECHA_FIN y CLIENTE se han agregado a los campos de origen. Si la disponibilidad
es NO, significa que el individuo está asignado a un trabajo. Las dos fechas se
alimentan en función de la duración del trabajo y el nombre del cliente se informa en el
campo del mismo nombre. Si el individuo está disponible, los valores de los campos se
alimentan con fechas ficticias y el campo cliente con un valor nulo: StrSQL = StrSQL &
", FECHA_INICIO = #1/1/2000#, FECHA_FIN = #1/1/2000#, CLIENTE = null ".

Los valores de tipo fecha se delimitan con el carácter # para identificarse como
tales.

Por contra si la disponibilidad pasa a NO, esta cadena se ignora ya que toda la
información relativa a la duración del trabajo y el nombre del cliente no se pueden
recuperar más que de la hoja Calendario Trabajo en la creación y la grabación de un
nuevo trabajo.

A continuación se añaden las condiciones (WHERE) en la cadena SQL. Es importante


incluir el apellido y el nombre del individuo si no quiere actualizar todos los registros de
la tabla: StrSQL = StrSQL & "WHERE APELLIDO=’" & Apostrofo( Sheets("Lista de
inscritos").Range("A" & LstMiembros.ListIndex + 2).Value) & "’" AND NOMBRE =
’" & Apostrofo( Sheets("Lista de inscritos").Range("B" & LstMiembros.ListIndex +
2).Value) & "’".

Antes de ejecutar la consulta, hay que volver a ejecutar la conexión con la base de datos
ya que es posible que esta última se haya interrumpido. Esto es especialmente así
después de la llamada al procedimiento Menu_CargaMenu. Se comprueba la conexión y
después se vuelve a ejecutar si es necesario: If IsObject(CnxBDD) Then. No es
necesario pasar de nuevo por las fases de búsqueda y verificación de la ruta ya que la
variable StrRuta ya se ha cargado y se ha validado su contenido.

A continuación, es posible ejecutar la consulta. Pero esta cadena SQL tiene una
particularidad más: la de ser una consulta de actualización. De hecho, no sólo recupera
registros como el comando SELECT. Actúa modificando los registros de la base de
datos. Además, vamos a utilizar el método Execute del objeto CnxBDD. Basta con
enviarle la consulta para que se aplique en la base de datos (CnxBDD.Execute StrSQL).
El método Execute se puede utilizar con las cadenas SQL de tipo UPDATE, INSERT
o DELETE.

c. La grabación de nuevos trabajos de la agencia

Durante la creación de un nuevo trabajo, es posible asignar individuos. Entonces ya no


están disponibles para otra asignación. La duración de esta no disponibilidad se define
con la fecha de inicio y de fin de las tareas. Toda esta información hay que tenerlas en
cuenta en la tabla Tab_Inscritos.

 Inserte el siguiente código en el procedimiento GuardarTrabajo del módulo


ModGestionCalendario justo después de los controles de entrada del nombre del
cliente y de la fecha de inicio de trabajo.

El programa recorre todas las tareas creadas por el trabajo con un bucle de tipo Do
While - Loop.

Para cada tarea encontrada, un consulta UPDATE actualiza la tabla Tab_Inscritos. De


nuevo se trata de una cadena SQL con una inserción condicional de campos a actualizar
en función de los datos que se encuentran en el calendario. Los campos
FECHA_INICIO y FECHA_FIN sólo se incorporan en la consulta si la fecha de inicio o
la fecha de fin se ha alimentado en la hoja. Los valores recuperados en las celdas de la
hoja Calendario Trabajo se concatenan en la cadena de caracteres, como en el caso de
los controles de formularios: If Range("E" & i).Value <> "" Then StrSQL = StrSQL &
", FECHA_INICIO = #" & Cells(i, 5).Value & "# ". Los datos devueltos en la consulta
se delimitan por #.

En la condición, el apellido y el nombre introducidos en el calendario permiten apuntar


al individuo a actualizar en la tabla con los campos APELLIDO y NOMBRE de la
tabla. Pero hay que tener en cuenta el hecho de que los apellidos y nombres se
concatenan en la asignación a una tarea del calendario.

Para resolver este problema, basta con concatenar los campos APELLIDO y NOMBRE
de la consulta: "WHERE (APELLIDO + ’ ’ + NOMBRE) = ’" & Range("C" & i).Value
& "’". En el lenguaje SQL, el signo + permite sumar valores numéricos pero también
concatena valores de tipo alfanumérico.

Después de la reconexión a la base de datos, la consulta de actualización se aplica a la


base de datos: CnxBDD.Execute StrSQL.

 Puede probar la aplicación. Si asigna personas a trabajos, estos últimos no


estarán disponibles en la tabla Constitución del equipo y habilidades de la hoja
Asignación Trabajo. También puede realizar modificaciones de disponibilidades
a partir del menú Miembros y del submenú Gestionar el estado de la hoja
Gestion de Perfiles.
 Pruebe también la grabación de un trabajo con apóstrofos.

Proteger la aplicación Gestión de Perfiles


Objetivos
En los capítulos anteriores, hemos visto a nuestra aplicación convertirse en ejecutable.
La identificación del usuario y el paso por un menú se encargan de controlar la
utilización de la aplicación y de proteger su contenido. Además, la asociación a una
base de datos permite externalizar los datos agrupándolos, mientras que antes se
guardaban en hojas de la aplicación. Incluso ocultas, estas hojas y su contenido
quedaban fácilmente accesibles a un usuario no autorizado.

Queda mucho por hacer en términos de seguridad en la aplicación Gestión de Perfiles.


Tanto a nivel de las entradas de usuario como a nivel del acceso al entorno de
desarrollo.
Vamos a añadir una contraseña para controlar el acceso al código de la aplicación.
También es necesario gestionar la seguridad de las hojas de trabajo y de las celdas de las
hojas para limitar las entradas a zonas que el programa necesita.

Por último, y aunque incluso con la identificación de los usuarios al iniciar la


aplicación, sólo los usuarios que tienen una contraseña válida pueden utilizar la
herramienta Gestión de Perfiles, hay que gestionar la navegación y accesibilidad a
ciertas funcionalidades de la aplicación.

La contraseña del IDE


Cuando la propiedad IsAddin está activa, no permite la apertura del IDE. Pero no ocurre
cuando el usuario escoge un menú y se descarga el formulario Frm_Menu. La propiedad
IsAddin pasa entonces a False dejando libre el acceso al código VBA. Vamos a crear
una contraseña a nivel del IDE para proteger el código de la aplicación.

1. Creación de una contraseña


 Ejecute la aplicación y después de identificarse, elija uno de los menús como
Consulta de perfiles o Creación de un calendario de trabajo. Puede abrir el IDE
con la combinación de taclas [Alt] y [F11].

 Haga clic con el botón secundario del ratón en la ventana del proyecto y seleccione en
el menú desplegable Propiedades de VBAProject.
 En el formulario VBAProject - Propiedades del proyecto, seleccione la pestaña
Protección.

 Marque la casilla Bloquear proyecto para visualización y teclee la contraseña


Agencia_2010. A continuación debe confirmarla en la siguiente caja de texto antes de
validar y cerrar el formulario con el botón Aceptar.
Para aumentar el nivel de protección de su contraseña, no dude en utilizar
mayúsculas, minúsculas, símbolos y operadores, para mezclar caracteres
alfanuméricos y numéricos.

Para activar su contraseña y probarla, tiene que cerrar el proyecto y volver a ejecutarlo.
Después de seleccionar un menú, ejecute el IDE.

Si intenta desplegar el árbol del proyecto, un InputBox le pide la contraseña antes de


autorizarle a ver el código de la aplicación.

Para su mayor comodidad, se aconseja que una vez haya validado la contraseña y
cuando el IDE esté accesible, realice la operación inversa deshabilitando la contraseña.

 Desmarque sólo la casilla Bloquear proyecto para visualización. El IDE está


disponible de nuevo. Si decide no poner a blanco la contraseña y su
confirmación, se le pedirá que introduzca la contraseña para acceder de nuevo a
este formulario y a las propiedades del proyecto para modificarlo.
La contraseña permanece disponible posteriormente cuando decida bloquear el código de la
aplicación. Generalmente es lo que se hace una vez se ha terminado el programa y la
aplicación está preparada para entregarse a los usuarios.

El control de las entradas del usuario


En una entrada del usuario, el control afectado por la entrada espera un cierto tipo de
caracteres. Si, por ejemplo, la aplicación pide introducir una edad, sólo se esperan
caracteres de tipo numérico. Pero hay que anticiparse a todas las situaciones e
implementar los controles adecuados.

Así, puede comprobar por código si la entrada es lo que el programa espera y detectar
una posible entrada no válida. La solución implica una interrupción del programa en
curso, la eliminación de la entrada no válida y el envío de un mensaje al usuario. Este es
el método que hemos aplicado en Gestión de Perfiles.

Existe una solución más radical que consiste en bloquear cualquier posibilidad de
introducir caracteres no deseados incidiendo directamente cuando el usuario escribe en
el teclado.

1. El código ASCII
Cada carácter tiene su equivalente en código numérico: es el código ASCII (American
Standard Code for Information Interchange). Este código permite identificar y trabajar
sobre las pulsaciones en el teclado. Hay que utilizar el evento KeyPress. Se activa
cuando el usuario presiona una tecla, lo que permite recuperar el código ASCII de la
tecla. Se devuelve un valor numérico que permite identificar la tecla presionada en el
teclado.
Vea la tabla que presenta los códigos de las principales teclas susceptibles de utilizarse
en un programa.
El código ASCII de la tabla identifica un total de 96 tecas pero existen más.

Los códigos entre 0 y 31 son caracteres de control ya que permiten hacer acciones como
saltos de línea o tabulaciones. Los códigos entre 48 y 57 son los números. Los códigos
entre 65 y 90 representan las letras del alfabeto en mayúsculas. Los códigos entre 97 y
122 representan las letras del alfabeto en minúsculas. El resto de códigos representan los
operadores y signos de puntuación.

2. El control de entradas en la identificación del


usuario
Vamos a proteger la entrada del usuario en el proceso de identificación. El usuario
rellena el control TextBox TxtNombreUsuario del formulario Frm_Identificacion antes
de introducir la contraseña. En esta entrada sólo son necesarias la teclas
correspondientes a las letras del alfabeto.

 Añada el procedimiento TxtNombreUsuario_KeyPress en el formulario


Frm_Identificacion.

Cada pulsación en las teclas del teclado genera un evento de tipo KeyPress recuperado
por el procedimiento con la instrucción ByVal. Conociendo el valor de las teclas,
podemos limitar las teclas disponibles a las letras del alfabeto y al retorno de carro.
Todas las teclas que no estén incluidas en la condición del If se deshabilitan
(KeyAscii.Value = 0). El retorno de carro (código ASCII igual a 8) se permite para
permitir al usuario volver hacia atrás en caso de error al teclear.

 Puede probar la entrada controlada del nombre de usuario en el proceso de


identificación al abrirse la aplicación.

La protección de las hojas en la aplicación


En las hojas de trabajo, algunas celdas tiene que llenarlas el usuario para alimentar los
procedimientos del programa. Puede tratarse por ejemplo de las fechas en la hoja
Calendario Trabajo. Otras celdas o rangos de celdas sirven al programa para restituir la
información almacenada en la base de datos o incluso los datos calculados por el
código.

La gran mayoría de las celdas no se tienen que rellenar porque no intervienen en el


código o contienen datos informados por el programa.

Vamos a gestionar la entrada en las hojas de la aplicación utilizando las funcionalidades


Excel como la protección de la hoja y el bloqueo de las celdas.

Vamos a comenzar por proteger la hoja Inicio.

1. Proteger la entrada en las celdas de una hoja


 Seleccione la hoja Inicio.
En esta hoja no se introducen datos y se debe bloquear.

 En la pestaña Inicio de la barra del menú principal, seleccione el menú Formato


y Proteger Hoja.
Se abre un cuadro de diálogo llamado Proteger hoja.

Desmarque todas las opciones seleccionadas en la lista Permitir a los usuarios de esta hoja de
cálculo:. En la zona de entrada de la contraseña, respetando la mayúscula, escriba: Inicio.
Después de haber validado la entrada con el botón Aceptar, un segundo cuadro de diálogo
llamado Confirmar contraseña le pide introducir de nuevo la contraseña en una zona llamada
Contraseña.

Si la contraseña de confirmación no es válida, un MsgBox informa al usuario.

 Aunque puede intentar introducir algún dato en la hoja Inicio, no puede


seleccionar ninguna celda.

Si a pesar de todo intenta escribir en la hoja, aparecerá el siguiente MsgBox:


2. El bloqueo y el desbloqueo de celdas
Por defecto, todas las celdas de las hojas del libro están bloqueadas. Pero este bloqueo
no es efectivo hasta que se activa la protección de la hoja. Es el principio que se ha
aplicado para la hoja Inicio.

Vamos a activar la protección de las hojas plantilla Asignación Trabajo y Calendario


Trabajo. Por el contrario esta vez, debemos seleccionar las celdas donde el usuario
puede realizar entradas. Habrá que desbloquearlas para que no se las tenga en cuenta en
la activación de la protección de la hoja.

 En el directorio Plantillas, abra el libro Calendario_Trabajo. Seleccione la hoja


Asignación Trabajo y active la protección de la hoja desactivando todas las
opciones de la lista de permisos y asignándole su nombre como contraseña.

En esta hoja, todas las celdas se dejan bloqueadas ya que no hay ninguna entrada directa
del usuario. La creación del equipo para alimentar las tareas del trabajo se hace con el
formulario Frm_Gestion_Equipo y el código asociado.

En la entrada de la contraseña, tenga en cuenta el blanco insertado en el nombre


de la hoja.

 Selecciona ahora la hoja Calendario Trabajo.

Si hace clic en una de las celdas de la hoja, el procedimiento


Worksheet_SelectionChange se activa y provoca un mensaje de error del IDE

Después de haber hecho clic en el botón Aceptar del MsgBox, se muestra el IDE en modo
depuración.
 Haga clic en el botón Restablecer del IDE para interrumpir el proceso de depuración.

 Comente todo el procedimiento Worksheet_SelectionChange para poder trabajar en la


hoja sin tener que interrumpir el proceso de depuración en cada selección de celda.

Hay que desbloquear las celdas de entradas del usuario. En la hoja Asignación Trabajo
se trata de las zonas de entrada del nombre del trabajo (B4), de las fechas de inicio de
trabajo (C7) y de inicio de visualización del calendario (C9). Hay dos métodos para
hacerlo.
 Con un clic en el botón secundario del ratón en la celda, seleccione en el menú
contextual el submenú Formato de celda.

Se muestra el cuadro de diálogo Formato de celda.


 Seleccione la pestaña Proteger, desmarque la casilla Bloqueada y valide
haciendo clic en el botón Aceptar.

El segundo método es mucho más rápido.

 Seleccione las tres celdas (B4, C7 y C9) al mismo tiempo y el menú Formato.
Haga clic en el submenú Bloquear celda. Como las celdas estaban bloqueadas
por defecto, esta acción las desbloquea. Con el mismo método, podría
bloquearlas de nuevo.

 Siempre pasando por la pestaña Inicio de la barra de menú principal, seleccione


el menú Formato y Proteger hoja.

Active la protección de la hoja Asignación Trabajo marcando la opción


Seleccionar celdas desbloqueadas en la lista de permisos asignándole su nombre
como contraseña.
El usuario puede seleccionar una de las celdas desbloqueadas para introducir datos.

1. Antes de cerrar el libro Calendario_Trabajo y después de haber registrado las


modificaciones realizadas en las hojas Asignación Trabajo y Calendario Trabajo,
no olvide reactivar el procedimiento Worksheet_SelectionChange que antes ha
comentado

Ahora sólo queda activar la protección de la hoja Gestion de Perfiles.

1. Ejecute la aplicación y seleccione el menú Consulta de perfiles. Una vez


aparezca la hoja Gestion de Perfiles, active la protección de la hoja desmarcando
todas las opciones de la lista de permisos asignándole su nombre como
contraseña.

Como para la hoja Asignación Trabajo, se han dejado bloqueadas todas las celdas ya
que no hay ninguna entrada directa del usuario. La gestión de los datos de esta hoja se
hace exclusivamente por el código contenido en los formularios y los procedimientos
llamados.

No es obligatorio asociar una contraseña en la activación de la protección de una


hoja. Pero en términos de seguridad, esto no tiene gran interés, ya que entonces
cualquier usuario puede ir al menú Formato para eliminar la protección.

3. La gestión de la protección de las hojas y del bloqueo


de celdas por código VBA
Para permitir la restitución de datos en las hojas de la aplicación, el código va a asumir
la gestión de la protección de las hojas y el bloqueo de las celdas. Vamos a crear un
nuevo módulo que se encargue de la seguridad de las hojas.
a. El módulo de seguridad de las hojas y las celdas

 Importe de la web del editor el módulo ModSeguridad.

Este módulo incluye dos procedimientos.

El procedimiento BloqueoHojas gestiona la activación y desactivación de la protección


de la hoja en el momento de la llamada. En la variable de tipo String StrPassHoja se
pasa por parámetro la contraseña adjunta a la hoja. Si la variable de tipo Booleano
BlEstado se pasa a True, se activa la protección de la hoja, sino se desactiva.

El método Protect asociado a la contraseña elimina la protección de la hoja. La


propiedad EnableSelection define el nivel de protección de las celdas de la hoja. Con el
valor xlUnlockedCells, el usuario puede desbloquear las celdas. Es la opción que se
aplica en la hoja Calendario Trabajo en la que el usuario tiene que poder acceder a las
zonas de introducción de fechas. El valor xlNoSelection impide cualquier selección en
la hoja.

El método Unprotect asociado a la contraseña desactiva la protección de la hoja activa.

b. La protección de la hoja Gestión de Perfiles

En la hoja Gestion de Perfiles, sólo las funcionalidades como la elaboración de la tabla


de perfiles (botón Lista de perfiles) o la clasificación de esta misma tabla (botón de
opción Clasificación por Apellido/Nombre o Clasificación por nivel) están afectadas por
la gestión de la seguridad. La primera de las dos funcionalidades crea una tabla en la
hoja que alimenta con datos. Durante la creación y la carga de los datos, se debe
eliminar la protección de la hoja y reactivarse una vez se ha terminado la operación. Lo
mismo ocurre en la segunda funcionalidad que, aunque no crea ninguna tabla con datos,
modifica esta última clasificando y reescribiendo en la hoja el orden de los registros.

 Inserte el siguiente código en el inicio del procedimiento


CmdListaPerfiles_Click de la hoja Gestion de Perfiles.

El procedimiento de bloqueo se llama con el parámetro False que significa que se va a


desactivar la protección de la hoja. El parámetro nombre de la hoja activa es una
contraseña a fin de permitir emular esta funcionalidad. Habríamos podido pasar por
parámetro el código ActiveSheet.Name pero tenemos que ser capaces de cambiar la
contraseña por lo que es importante dejarla separada del nombre de la hoja.

Una vez cargada la tabla, hay que reactivar de nuevo la protección de la hoja.

 Inserte al final del procedimiento CmdListaPerfiles_Click el siguiente código.

Aquí, el procedimiento de reactivación se llama con el parámetro True que significa que
se va a reactivar la protección de la hoja. La contraseña siempre acompaña a la llamada
de la función.

Pero existe en el código del procedimiento dos comprobaciones susceptibles de


interrumpir el procedimiento que se está ejecutando y que pueden impedir a éste último
ir al final del código y reactivar la protección de la hoja.

 Inserte de nuevo la llamada al procedimiento BloqueoHojas como en el


siguiente código.
Ahora se tienen en cuenta las dos salidas del procedimiento por la instrucción Exit Sub,
una en la validación de entrada del usuario en el InputBox y la otra en el número de
perfiles a cargar en la tabla.

En cuanto a las opciones de clasificación, la llamada para la desactivación de la


protección de la hoja se hace justo después de comprobar si hay algún valor, lo que
puede provocar la interrupción de la ejecución del procedimiento. La llamada para la
reactivación de la protección de la hoja se hace al final del procedimiento.

 Inserte las llamadas al procedimiento de gestión de la protección de la hoja


como en el siguiente código.
 Ahora puede probar las diferentes funcionalidades de la hoja asociadas a la
gestión de la protección.

c. La protección de la hoja Asignación Trabajo

En la creación de la lista de individuos a asignar a las tareas de un trabajo que se está


creando, la problemática parece igual a la de la hoja Gestion de Perfiles. Hay una carga
de datos en una tabla a la que a continuación se le da formato. Pero existe una diferencia
ya que todo el proceso se realiza a través del código del formulario
Frm_Gestion_Equipo. Cada clic en el ListBox Lst_Equipo carga un nuevo individuo en
la hoja Asignación Trabajo.
Sólo hay que insertar la llamada al procedimiento BloqueoHojas al principio y al final
del código del formulario. Es decir en la carga y la inicialización del formulario en el
procedimiento de evento UserForm_Initialize y justo antes de descargar el formulario
en el procedimiento de evento UserForm_Terminate. Entre cada selección de la lista
desplegable, queda desactivada la protección de la hoja Asignación Trabajo. Pero el
formulario está abierto en modal (ShowModal = True) y el usuario no tiene acceso a los
objetos que están fuera del formulario. No puede realizar entradas en la hoja activa.

 Inserte la llamada al procedimiento para la desactivación de la protección de la


hoja al inicio del procedimiento de evento UserForm_Initialize.
 Inserte a continuación la llamada al procedimiento para la reactivación de la
protección de la hoja al final del procedimiento de evento UserForm_Terminate
justo antes de la creación del rango de celdas de las profesiones y sobretodo
antes de la salida anticipada del procedimiento por una instrucción Exit Sub, si
la lista se ha rellenado correctamente. Esto nos ahorra tener que introducir
código adicional.
d. La protección de la hoja Calendario Trabajo

La gestión de la seguridad se hace más compleja en la hoja Calendario Trabajo. De


hecho, esta hoja integra la recuperación de datos por código. Se trata de datos extraídos
de la base de datos BDD_Agence.accdb o de datos calculados por el programa. Estos
cálculos se basan en los datos de la base datos pero también en las entradas del usuario
en las celdas que no están bloqueadas. Por último, la recuperación de datos por el
código genera nuevas zonas de entradas que hay que crear.

Aparte del nombre del cliente, el usuario introduce las fechas del inicio del trabajo y el
inicio de la visualización del calendario. La fecha de inicio de visualización la puede
modificar el usuario directamente o indirectamente en la introducción o modificación de
la fecha de inicio de trabajo. En ambos casos, esta acción implica una modificación de
la visualización de la tabla y entonces las columnas se marcan o desmarcan. Esto
necesita una gestión del bloqueo de la hoja Calendario Trabajo.

 Inserte las llamadas al procedimiento de gestión de la seguridad de la protección


de la hoja en el procedimiento de evento Gestion_Entrada del módulo
ModIntroduccionCalendario, en el bloque de código de las modificaciones de la
fecha de inicio de visualización.

La modificación de la visualización del calendario se ejecuta con el procedimiento


InicializarCalendario del módulo ModGestionCalendario.

 Inserte la llamada para la desactivación de la protección al inicio del


procedimiento de la hoja al inicio del procedimiento y la llamada de reactivación
de la protección al final. No olvide insertar una segunda llamada de reactivación
de la protección justo antes de la salida del procedimiento (Exit Sub) cuando el
bucle Do - While ha terminado de recorrer todo el calendario.

Recuerde que en la inserción de una nueva tarea (botón Insertar tareas), se llama al
procedimiento InsertarTareas del módulo ModGestionCalendario. Se crea una máscara
con dos listas desplegables para elegir el individuo y la profesión.

 Inserte la llamada para la desactivación de la protección al inicio del


procedimiento después de la comprobación de la existencia de asignaciones y de
la fecha de inicio del trabajo.

 Inserte la llamada de reactivación de la protección de la hoja al final del


procedimiento.

Pero hay que dar la posibilidad al usuario de realizar la selección en las dos listas
desplegables, de introducir una fecha de inicio de tarea y de asignar un número de días.
Se deben desbloquear estas celdas al mismo tiempo que se añade la tarea al calendario.

 Inserte la llamada de desbloqueo de celdas de la hoja al final del procedimiento


justo después de la inserción de la máscara de entrada y antes de la numeración
de la tarea.
El rango de celdas que se tiene que desbloquear se pasa por parámetro en la llamada.

 Para introducir una fecha de inicio de tarea, debe insertar las llamadas de
desactivación y de reactivación de la protección de la hoja en el procedimiento
de evento Gestion_Entrada del módulo ModIntroduccionCalendario, en concreto
en el bloque de código de las modificaciones de la fecha de inicio de tarea al
final del procedimiento.

 Para la entrada del número de días asignados, debe insertar las llamadas de
desactivación y de reactivación de la protección de la hoja en el mismo procedimiento
que antes. Pero esta vez la inserción se hace en el bloque de código del control de la
entrada del número de días asignados.
La introducción de días asignados asociados a la fecha de inicio de tareas comporta la
ejecución de los procedimientos de cálculo y de informe en el histograma de la tarea en
cuestión.

Se llama al procedimiento Gestion_Fechas del módulo ModGestionFechas.

 Inserte en el bucle Do - While que lista todas las tareas del calendario, las
llamadas de desactivación y reactivación de la protección de la hoja. Deben estar
antes y después de la recuperación del estado del día y de la fecha de fin de
tarea.

Al salir del bucle, se ejecuta el procedimiento CalendarioTrabajo del módulo


ModGestionFechas.

 Inserte la llamada para la desactivación de la protección de la hoja en el inicio


del procedimiento y la llamada de reactivación al final.
 Puede probar todas las funcionalidades del Calendario de la aplicación.

La recuperación de los permisos de usuario y la navegación en la


aplicación
La seguridad de la aplicación pasa también por la gestión de la navegación y de la
accesibilidad en los diferentes menús. Todos los usuarios de una aplicación no tienen
porqué tener un mismo perfil. De este modo, en la aplicación pueden existir datos
confidenciales o funcionalidades reservadas que estarán accesibles a algunos perfiles y
no para otros. Es pues necesario recuperar el perfil del usuario en el momento de su
identificación y mostrarle una navegación con menús adaptados a sus permisos.

1. El perfil de usuario
Debemos recuperar el perfil de usuario para gestionar la navegación y los menús en la
aplicación Gestión de Perfiles.

a. La tabla de usuarios

La tabla Tab_Usuarios almacena la información relativa a cada usuario: su nombre, su


contraseña y sus permisos.

A modo de ejemplo, hemos definido dos perfiles: un perfil User que es el perfil de los
usuarios de base que tienen derechos limitados en la aplicación y el perfil Admin que
está reservado a los usuarios que tienen acceso ilimitado a la herramienta.

b. La recuperación del perfil del usuario

La recuperación del perfil se hace en la identificación en el formulario


Frm_Identificacion. Si el nombre y la contraseña del usuario están en la base de datos,
se recupera también el perfil del usuario. Para ello, basta con añadir el campo en la
consulta SQL y almacenarlo en una variable pública que estará disponible a lo largo de
toda la sesión del usuario y de su navegación en la apliación.

 Inserte en el SELECT de la consulta de identificación del usuario, el campo


Permisos_Usuario.

 Inserte una nueva variable pública de tipo String llamada StrPerfil en el módulo
ModDeclaration.

 Ahora puede escribir la instrucción de recuperación del perfil de usuario en el


procedimiento de evento CmdValidationUser_Click justo antes de cerrar el Recordset.
2. La gestión de los menús
Con la variable StrPerfil, vamos a poder gestionar la accesibilidad de los menús y las
funcionalidades en toda la aplicación.

a. Un formulario de menús modulable

El formulario Frm_Menu muestra cierto número de accesos a las funcionalidades de la


aplicación.

Podríamos decidir que a partir de ahora la posibilidad de cambiar la base de datos sea un
operación delicada y que sólo un usuario con permisos de tipo Admin pueda efectuar
esta operación.

 Inserte un nuevo procedimiento de evento en el formulario Frm_Menu.

En la activación del formulario, si el valor de perfil recuperado en la variable StrPerfil es


diferente de Admin, la propiedad Visible del botón CmdRutaBDD pasa a False.
El botón Seleccionar una base de datos no es visible pero está en el formulario Frm_Menu.
Todo lo que hay por debajo de este botón ahora no está disponible para el usuario.

Es posible deshabilitar un control de un formulario poniendo su propiedad


Locked a True. El control queda visible en el formulario pero con un aspecto
atenuado. El usuario no puede activarlo. Pero a menudo es preferible mostrar
ciertas funcionalidades sólo a los usuarios que las van a utilizar y utilizar la
propiedad Visible.

Además de deshabilitar un botón del formulario para bloquear el acceso a una o más
funcionalidades, también es posible bloquear la instalación de estas últimas.

Vamos a reservar la utilización del menú Miembros considerado también crítico sólo a
los usuarios que tengan el perfil Admin.
 Inserte el siguiente código en el procedimiento de evento CmdConsultaPerfiles_Click
del formulario Frm_Menu. Hay que insertarlo al final del procedimiento antes que se
visualice la hoja Gestion de perfiles.

A partir de ahora, el procedimiento de creación de la barra Miembros sólo se llama si la


variable StrPerfil contiene el valor Admin.
Puede probar la aplicación alternando la identificación (Nombre y Contraseña) con los perfiles
Admin y User.

Das könnte Ihnen auch gefallen