Aula Macedonia


Curso de Programación en VBA para Excel


Artículo realizado por
Iñaki Ecenarro.





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

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


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

Los cuadros de diálogo en Office 97 son mucho más potentes que en la versión anterior. Se han añadido muchas opciones, como la posibilidad de definir eventos, utilizar controles ActiveX además de los incluidos en Excel (si no sabes qué es un control ActiveX no tiene demasiada importancia, es un tema avanzado que quizá algún día tratemos), etc.

Nuestro primer cuadro de diálogo va a ser muy sencillo: vamos a presentar un cuadro de diálogo en el que el usuario puede introducir un número, y si pulsa "Aceptar" copiaremos el número introducido en la celda activa. Si el usuario pulsa "Cancelar" no haremos nada.

Lo primero es ir al editor de Visual Basic, utilizando la opción "Herramientas, Macro, Editor de Visual Basic", o simplemente pulsando Alt-F11.

En la parte izquierda de la pantalla tendremos el "Explorador de Proyectos" y la ventana de "Propiedades". Igual que antes, si no puedes ver estas ventanas utiliza el menú "Ver" para hacer que aparezcan. En el "Explorador de Proyectos" aparecen todos los "proyectos" de VBA: cada libro que tengamos abierto es un proyecto. Dentro de cada libro aparecen todas las hojas del libro y también los módulos y cuadros de diálogo que crearemos más adelante.

En la ventana de "Propiedades" aparecen las propiedades del objeto que tengamos seleccionado en ese momento. Supongo que a estas alturas ya debe estar claro el concepto de "propiedad" de un objeto. Por ejemplo, vamos a ir a un proyecto de VBA en el "Explorador de Proyectos". Dentro de él veremos las hojas de cálculo del libro, y vamos a seleccionar una de ellas. En la ventana de "Propiedades" van a aparecer las propiedades de la hoja seleccionada. Por ejemplo, la primera propiedad que vemos es la propiedad Name, que ya conocemos. Podemos utilizar la ventana de "Propiedades" para cambiar las propiedades del objeto seleccionado.

Ahora para crear nuestro cuadro de diálogo vamos a utilizar la opción "Insertar, Userform" (Userform es el nombre que da Excel 97 a los cuadros de diálogo).

Cuadro de herramientas

En este momento vemos en la parte derecha un cuadro de diálogo vacío, y por otro lado veremos el "Cuadro de herramientas", en el que están todos los controles que podemos poner en el cuadro de diálogo. Si no aparece el Cuadro de Herramientas utiliza la opción "Ver, Cuadro de herramientas" para que aparezca.

Los controles del "Cuadro de herramientas" son los típicos de cualquier cuadro de diálogo que podemos ver en cualquier aplicación de Windows:

Diálogo con los controles más utilizados

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

Hay más propiedades, pero su uso es bastante sencillo, y consultando la ayuda encontrarás la descripción de todas las propiedades.

Vamos con nuestro diálogo: lo primero es cambiarle el nombre; vamos a la ventana de Propiedades y en la propiedad Name, escribimos por ejemplo "ufPrimero". Luego en la propiedad "Caption" escribiremos "Mi primer UserForm". Las demás propiedades las dejamos como están, aunque si quieres cambiar alguna que afecte a la presentación del diálogo (color de fondo, efectos especiales, etc) puedes hacerlo tranquilamente.

En cualquier momento puedes probar tu cuadro de diálogo seleccionándolo con el ratón y utilizando la opción "Ejecutar, Ejecutar Sub/Userform" (o más rápido pulsando F5 o el botón de ejecutar Botón para ejecutar una macro/userform). Para cerrar el diálogo tendrás que utilizar la "X" que aparece en la parte superior derecha, porque todavía no hemos añadido ningún botón para cerrar el diálogo.

Como hemos dicho antes, en nuestro cuadro de diálogo queremos que el usuario escriba un número. Para que pueda hacerlo, tendremos que poner un cuadro de texto en el diálogo. Para ello pulsamos en el UserForm para que aparezca el "Cuadro de Herramientas" y en éste pulsamos sobre el control "Cuadro de Texto" Cuadro de texto. Una vez seleccionado el "Cuadro de Texto" pulsamos en cualquier parte del UserForm y veremos que aparece un cuadro de edición. Podemos utilizar el ratón para moverlo y cambiarle el tamaño.

Pulsando con el ratón, seleccionaremos el cuadro de edición, y como de costumbre veremos que en la ventana de "Propiedades" aparecen todas las propiedades del objeto "Cuadro de Texto" (TextBox en inglés), entre las que se encuentran:

Las propiedas sobre la apariencia del control son parecidas a las que hemos visto antes (BackColor, ForeColor, SpecialEffects). El resto de propiedades se pueden consultar en la ayuda. Aunque parezca que nos estamos dejando muchas cosas, una vez que empezamos a tener claras las cosas el utilizar propiedades que no hemos usado nunca es muy sencillo. O sea, que por ahora nos centramos en lo básico.

Bueno, ahora vamos a nuestro cuadro de diálogo. Seleccionamos nuestro cuadro de edición, lo colocamos en una posición que nos guste, y vamos a las propiedades. Primero la propiedad Name, que en este caso vamos a dejar tal como está, TextBox1. No suele ser aconsejable dejar estos nombres, porque si tienes varios cuadros de edición en un diálogo al final no sabes a cuál te estás refiriendo, pero como en este caso sólo vamos a tener un cuadro de edición no nos importa demasiado. Ahora vamos a la propiedad "TextAlign" y vamos a seleccionar la opción "fmTextAlignRight" para alinear el texto a la derecha, ya que lo que queremos es que le usuario introduzca un número. Por ahora no vamos a hacer nada más con este control.

Si ejecutamos el cuadro de diálogo veremos que podemos introducir un valor en el cuadro de edición que hemos creado, pero aparte de eso no podemos hacer mucho más.

Lo siguiente que vamos a hacer es poner un texto descriptivo para el cuadro de edición. Para ello seleccionamos del "Cuadro de herramientas" el control "Etiqueta" Etiqueta, y pulsamos en el UserForm para crear un control del tipo etiqueta. Utilizando el ratón le podemos cambiar el tamaño y moverlo, para ponerlo a la izquierda del control de edición que hemos creado antes.

En la ventana de propiedades de nuestro nuevo control (recuerda que tienes que seleccionarlo para poder ver sus propiedades en la ventana de propiedades) veremos como siempre la lista de propiedades. La propiedad Name la vamos a dejar como está, ya que no vamos a referirnos a este control en el código, y no nos interesa su nombre: normalmente los controles de etiqueta se utilizan sólo para poner un texto en el diálogo, y no se suelen referenciar desde el código VB. La propiedad que nos interesa es "Caption", en la que escribiremos el texto que queremos que aparezca en el cuadro de diálogo, por ejemplo "Escribe un número:".

Si colocamos bien los dos controles (utilizando por ejemplo la opción "Formato, Alinear, Medio), ya tenemos un diálogo algo más completo.

Lo típico en estos cuadros de diálogo es que en la parte inferior haya dos botones, uno para "Aceptar" y el otro para "Cancelar". Vamos a colocar estos dos botones, empezando por el de "Cancelar" que es un poco más fácil.

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

Por ahora dejamos el resto de propiedades de los botones. Bueno, hasta ahora le hemos dado a nuestro botón el nombre "cbCancel", le hemos puesto el texto "Cancelar" y hemos dado el valor "Verdadero" a la propiedad "Cancel".

Si ejecutamos el cuadro de diálogo veremos que tenemos un botón muy bonito, pero que no hace absolutamente nada. Para que haga algo tenemos que meternos con un concepto muy importante de la programación orientada a objetos, los Eventos.

A estas alturas ya deberían estar claros los conceptos de Objeto, Propiedad y Método. En Excel, un objeto es una variable que representa cualquier elemento de Excel, como un rango, un libro, una celda, o un UserForm. Todos los objetos tienen propiedades (como Cell.Value, Workbook.Name o UserForm.BackColor), y métodos (como Range.ClearContents o UserForm.Show).

Además de propiedades y métodos los objetos tienen también "eventos". He mirado en la ayuda y no he encontrado una definición de evento, y tampoco me atrevo a dar una, pero voy a ver si puedo explicar el concepto. Imaginemos que tenemos un control, como por ejemplo el control de edición que hemos colocado en nuestro diálogo. Cuando sucede un "evento" de los que este control "entiende", Excel llamará a una función con un nombre especial, siempre que hayamos definido esa función (si no la hemos definido, no pasa nada, el "evento" se ignora). Un ejemplo de evento es que el usuario mueva el ratón por encima de nuestro control. Cada vez que el ratón se mueve se produce un evento "MouseMove", y entonces Excel llamará a la rutina TextBox1_MouseMove( ... ), en caso de que hayamos definido esa rutina, lo que haremos en caso de que nos interese hacer algo cada vez que el ratón pase por encima de nuestro control. El nombre de la rutina es especial: primero va el nombre del control (recuerda que lo habíamos dejado tal como nos lo había puesto Excel, TextBox1), luego un carácter de subrayado ("_"), y luego el nombre del evento.

Otro ejemplo de evento: queremos que el usuario introduzca un número en el cuadro de edición, pero si lo probamos veremos que se puede escribir cualquier carácter que no sea un número. Cada vez que el usuario pulsa una tecla se produce el evento "KeyPress", que podemos utilizar para ignorar la tecla pulsada por el usuario si éste pulsa una tecla que no es un número. Más adelante veremos cómo se hace.

Bueno, no sé si ha quedado muy claro, pero creo que con un poco de práctica espero que sí. Dominar los conceptos de objeto, propiedad, método y evento es muy importante, pero no sólo para programación en Visual Basic for Applications, sino que estos conceptos son básicos en todos los lenguajes de programación orientada a objetos (Visual Basic, Borland Delphi, Java, etc.). De hecho, si dominas esos conceptos con cuatro cosas más podrás programar en cualquiera de esos otros lenguajes.

Bueno, sigamos con los eventos. Vamos a centrarnos ahora en nuestro botón de "Cancelar". El evento más normal para un botón es que el usuario lo pulse con el ratón (o con el teclado). Cuando esto ocurra, se generará un evento Click, y llamará a la rutina cbCancelar_Click(). (cbCancelar es el nombre que habíamos dado al control, y Click es el nombre del evento). Lo más fácil para crear un evento es seleccionar un control y luego pulsar el botón derecho y seleccionar la opción "Ver Código". Veremos una página de código VB en la que Excel habrá escrito la cabecera de un evento para dicho control (la verdad es que no sé cuál de los eventos coge, supongo que cogerá el más utilizado). En nuestro caso, si pulsamos sobre el botón "Cancelar" con el botón derecho y luego "Ver código" en la página de código veremos lo siguiente:

Private Sub cbCancelar_Click()

End Sub

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

Otra cosa, la página de código que estamos viendo es como un módulo normal en el que escribimos nuestro código, con la particularidad de que no sale en la lista de módulos en el "Explorador de Proyectos", ya que es un módulo asociado al Userform.

Para crear una función para cualquier otro evento tenemos en la parte superior de la ventana de código dos "persianas". En la persiana de la izquierda tenemos el objeto sobre el que queremos definir una función para un evento. En la persiana de la derecha tenemos todos los eventos que pueden ocurrir para el control seleccionado en la persiana de la izquierda. Si queremos definir la función para otro evento lo único que tenemos que hacer es seleccionar otro evento en esta persiana, y Excel insertará en el código la cabecera para la función que se va a ejecutar cuando se de ese evento.

Bueno, lo que queremos hacer cuando el usuario pulsa el botón de Cancelar es simplemente cerrar el cuadro de diálogo. Tendremos que cerrar el cuadro de diálogo cuando Excel nos avise de que ha ocurrido un evento Click, es decir, dentro de la función cbCancelar_Click().

La instrucción que se utiliza para cerrar el UserForm es "Unload", que sirve para quitar un objeto de la memoria. La instrucción Unload requiere un parámetro, que utilizaremos para indicarle cuál es el objeto. En nuestro caso utilizaremos la palabra clave "Me", que apunta al objeto en el que se está ejecutando el código, es decir, nuestro UserForm.

Nuestro "manejador de eventos" para el evento Click del botón cbCancel quedaría así:

Private Sub cbCancelar_Click()
   Unload Me
End Sub
Nuestro primer Userform

Cuando el usuario pulse el botón de Cancelar se generará un evento Click, y Excel llamará a nuestra función, que utilizará la instrucción Unload para cerrar el diálogo. Fíjate en que si pulsas la tecla "Escape" el diálogo se cierra igual que si hubieses pulsado con el ratón sobre el botón: esto es debido a que hemos dado el valor verdadero a la propiedad "Cancel" del botón Cancelar.

Después de probar el cuadro de diálogo y comprobar que nuestro botón de Cancelar funciona perfectamente nos queda añadir el botón de Aceptar. Para crear el botón seleccionamos en el "Cuadro de Herramientas" el "Botón de comando" y lo colocamos en el UserForm. Luego le ponemos su nombre (cbAceptar por ejemplo), cambiamos su texto (ponemos Aceptar) y le damos el valor "Verdadero" a la propiedad Default para que si el usuario pulsa Enter sea como si hubiese pulsado con el ratón sobre el botón.

Ahora nos queda todo el tema de los eventos. El procedimiento es el mismo que con el botón de Cancelar, con la única diferencia de que antes de cerrar el cuadro de diálogo (con la instrucción Unload) deberemos hacer lo que queremos que nuestro diálogo haga, es decir, copiar el contenido del cuadro de edición TextBox1. La función sería la siguiente:

Private Sub cbAceptar_Click()
    ActiveCell.Value = TextBox1.Value
    Unload Me
End Sub

Esta función es prácticamente igual que la que hemos escrito para el botón Cancelar, con la excepción de que antes de cerrar el cuadro de diálogo escribimos otra línea, que se encarga de copiar en la celda activa (ActiveCell) el contenido del cuadro de edición. Fíjate como accedemos al contenido del cuadro de edición, a través del nombre del control (TextBox1) y su propiedad Value, que nos devuelve el valor numérico de lo que se ha introducido en el control (si hay caracteres no numéricos la propiedad Value nos devolverá el valor 0).

Si probamos ahora el cuadro de diálogo veremos que ya funciona perfectamente, ya hemos conseguido que nuestro primer UserForm funcione. El único problema que tiene es que en el cuadro de edición el usuario puede escribir cualquier caracter además de números. Para evitar esto ya he adelantado antes que hay que utilizar el evento KeyPress del cuadro de edición, pero eso lo veremos más adelante.

- El segundo cuadro de diálogo.

Userform de Datos Personales

Vamos a hacer otro cuadro de diálogo: tenemos en una hoja de cálculo una celda con el nombre de una persona y otra celda con el apellido. Queremos crear un Userform que permita al usuario editar ese nombre y apellido, y si pulsa Aceptar en el cuadro de diálogo los valores de esas celdas deben actualizarse con lo introducido por el usuario.

Si te fijas en el fichero de ejemplo verás las dos celdas que incluyen el nombre y el apellido. A estas celdas les he dado el nombre "rngNombre" y "rngApellido", respectivamente. Cuando hagamos referencias a celdas de hojas de cálculo en nuestro código es muy conveniente utilizar nombres de rangos en lugar de referencias absolutas (como por ejemplo C12), ya que si utilizamos nombres de rangos y movemos esas celdas no tenemos que hacer ningún cambio en el código, lo que deberemos hacer si utilizamos referencias absolutas.

Repetimos los pasos anteriores:

Vamos con los eventos: para el botón Cancelar la función que debemos escribir es exactamente igual que en el caso anterior:

Private Sub cbCancelar_Click()
   Unload Me
End Sub

Lo único que hace es cerrar el cuadro de diálogo al producirse el evento "Click" del botón Cancelar.

La función para el botón Aceptar también es muy similar a la anterior:

Private Sub cbAceptar_Click()
    Range("rngNombre").Value = tbNombre.Text
    Range("RngApellido").Value = tbApellido.Text
    Unload Me
End Sub

Esta función se ejecuta también cuando se produce el evento Click del botón llamado cbAceptar. Antes de cerrar el cuadro de diálogo debemos guardar en las celdas de la hoja de cálculo los valores de los cuadros de texto. Para ello utilizamos un objeto Range (a estas alturas somos unos autenticos expertos en el objeto Range), y le asignamos a su propiedad Value el valor de la propiedad Text del objeto TextBox. Esta es la única novedad, la utilización de una propiedad de los objetos TextBox (tbNombre y tbApellido).

Si ejecutamos ahora el cuadro de diálogo veremos que funciona perfectamente: si cambiamos los nombres en el UserForm y pulsamos Aceptar veremos que las celdas de la hoja de cálculo han cambiado y ahora contienen los nuevos nombres.

Pero hay una pequeña opción que se nos ha escapado: si vamos directamente a la hoja de cálculo, cambiamos los nombres en sus celdas, y ejecutamos el Userform, veremos que los controles de edición no tienen ahora los nombres actualizados, ya que no recogen los cambios que hemos hecho nosotros directamente en la hoja de cálculo.

Para eso vamos a utilizar también los eventos. En esta ocasión vamos a utilizar un evento del Userform (sí, los UserForms también tienen eventos). Se trata del evento Initialize, que se produce justo antes del que el UserForm aparezca en la pantalla. Ese es el momento para hacer cualquier cambio en el Userform, como poner un texto en un control, que es lo que queremos hacer.

Por lo tanto, seleccionamos el UserForm, pulsamos con el botón derecho y luego la opción "Ver código" (también se puede hacer doble-click sobre el Userform) y en la persiana de la derecha seleccionaremos el evento Initialize. Excel creará en ese momento la cabecera de nuestra función:

Private Sub UserForm_Initialize()

End Sub

Ahora tenemos que escribir el código que queremos que se ejecute antes de que se muestre el Userform. Lo que queremos hacer es poner en los dos cuadros de texto (el de nombre y el de apellido) el contenido de las celdas que tienen esos datos. Para ello utilizaremos el siguiente código:

Private Sub UserForm_Initialize()
    tbNombre.Text = Range("rngNombre").Value
    tbApellido.Text = Range("rngApellido").Value
End Sub

No creo que tenga demasiada dificultad. Es lo mismo que hemos escrito para el botón Aceptar pero al revés, es decir, damos a los cuadros de texto del Userform el valor que tienen las celdas de la hoja de cálculo.

Pues ya está, ahora sí que el cuadro de diálogo funciona perfectamente, tanto si hacemos los cambios en el UserForm (se actualizará la hoja de cálculo si pulsamos Aceptar) como si hacemos los cambios en la hoja de cálculo (se actualizará el UserForm antes de aparecer en pantalla, porque se habrá ocurrido un evento Initialize).

Bueno, hasta aquí llega esta tercera entrega. Todavía nos queda mucho por ver sobre los cuadros de diálogo (o UserForms, o formularios, como prefieras), pero eso lo dejamos para la próxima entrega. Hasta entonces te toca practicar, y sobre todo recuerda que lo más importante es tener claros los conceptos importantes: objetos, propiedades, métodos y eventos.


Recuerda que los ejemplos de este capítulo están incluídos en este fichero: Excel3.xls
(117kbs)




AULA MACEDONIA
a
MACEDONIA Magazine