martes, 12 de agosto de 2014

Artículo: Ejecutar una Macro o Código VBA desde un Botón de la Cinta de Opciones.

Resultado final del artículo
Resultado final del artículo.
En el artículo anterior creamos varios botones en una ficha personalizada y os hablé de algunas de las propiedades de los botones que se crean con la etiqueta "button". Pero no os hablé de la propiedad más importante, la que permite indicar que tiene que suceder cuando se pulsa el botón, la propiedad "onAction". En ella podemos indicar que macro o código VBA queremos que se ejecute al ser pulsado el botón. En este artículo la vamos a usar y veremos cómo enlazar los botones de la Cinta de Opciones con nuestras Macros o código VBA.

Para la explicación voy a seguir con el documento que creamos en el artículo anterior, pero en mi caso le he quitado el grupo "Albaranes" de la ficha "Facturación" y la ficha "Productos". He quitado casi todo lo que por el momento no vamos a utilizar. Si no lo tenéis, lo podéis descargar del siguiente enlace.


En la primera imagen del artículo, podemos ver cuál será el resultado visual final. Como podéis ver aparecen los dos botones que añadimos en el artículo anterior y uno tercer botón nuevo. Entre el segundo y el tercero he metido un separador que consiste en una línea vertical de separación. Primero vamos a realizar estos cambios, añadiremos el tercer botón y el separador.


Podemos utilizar el control separador para separar controles en los grupos de controles
Separador para separar controles en los grupos de controles.

Abrimos el documento en el Custom UI Editor y vamos con las modificaciones en el aspecto visual del grupo de controles "Facturas". En algunas ocasiones puede que queramos separar controles dentro de un mismo grupo, por ejemplo en este caso he querido separar de los otros dos el botón que permitiría eliminar facturas. Como es un poco peligros he decidido separarlo un poco. Para esto tenemos un control que podemos definir en el código XML y que se utiliza como separador, escribimos la siguiente líneas después de los dos botones que tenemos definidos del artículo anterior.

<separator id="separador01" />
<button id="botonEliminarFactura" label="Eliminar" size="large" imageMso="ReviewDeleteComment" />

Añadimos un separador con la etiqueta separator y un botón con button
Añadimos un separador con la etiqueta separator y un botón con button.

La primera línea que hemos añadido es completamente nueva, en ella usamos la etiqueta "separator" para añadir un separador entre los dos botones que ya existen y el que creamos en la siguiente línea. Como ya os he comentado como separador se crea una línea vertical, en la siguiente imagen lo podéis ver. Es una etiqueta muy sencilla lo único que hemos utilizado en su interior es la propiedad "id" para darle un identificador. Como podéis observar, al igual que la etiqueta "buton" no tiene etiqueta de cierre, se define en una sola etiqueta. Como en su interior no hay otros elementos no hace falta, todo en una sola etiqueta.

Después del separador hemos añadido otro botón que usaremos para eliminar facturas. Sobre los botones ya os hablé en el artículo anterior y de momento no hay nada nuevo que contaros en este. Para definirlo he utilizado las propiedades de las que ya os hablé.

Aspecto definitivo de la ficha Facturación
Aspecto definitivo de la ficha Facturación.

Una vez que tenemos el aspecto visual creado, vamos con el lógico, con el funcionamiento. Como os he dicho antes, de los botones no hemos utilizado la propiedad más importante que tienen, la que nos permite indicar que pasará cuando se pulsen. ¿De qué nos sirve un botón si no pasa nada al pulsarlo? De los tres botones que tenemos, dos los vamos a modificar para que hagan algo al ser pulsados. Va ser muy sencillo, ya os he dicho que en estos artículos sobre todo me quiero centrar en conocer todo lo relacionado con el XML. Ya tendremos tiempo de crear código más complejo para ser ejecutado desde la Cinta de Opciones. De momento lo único que pasará es que cuando pulsemos el botón "Nueva" se añadirá una nueva hoja al documento y al pulsar el botón "Eliminar" se eliminará la hoja en la que estamos en ese momento. Evidentemente ninguna de las dos tareas se corresponde con crear nuevas facturas y eliminarlas, pero ya os digo que eso no es lo que estamos aprendiendo en estos artículos. Vamos con el primero, modificamos el código del primer botón para añadir una nueva propiedad, la propiedad "onAction":

<button id="botonNuevaFactura" label="Nueva" size="large" imageMso="FileNew" onAction="Facturas.CrearFactura"/>

La propiedad "onAction" es la responsable de controlar que se hace cuando se pulsa un control, en este caso un botón. En ella tenemos que indicar el nombre de la macro o procedimiento VBA que queremos que se ejecute al ser pulsado el botón. Aquí le he dicho que se ejecutará un procedimiento llamado "CrearFactura" que está situado dentro de un módulo llamado "Facturas". Ahora diréis, ¿Y dónde está esto? Bueno pues cuando acabemos en el Custom UI Editor debemos ir a Excel para crear ambas cosas, el módulo y el procedimiento. Es cuanto llegará el momento de programar. En cuanto al XML ya no hay nada más que hacer, esto es todo para este botón. Nos falta hacer lo mismo con el tercer botón, el que eliminará las facturas.

<button id="botonEliminarFactura" label="Eliminar" size="large" imageMso="ReviewDeleteComment" onAction="Facturas.EliminarFactura"/>

Nada nuevo, en este caso le indicamos que cuando se pulse el botón se ejecutará el procedimiento "EliminarFactura" situado en el módulo "Facturas". El código XML de todo el documento quedará como veis en la siguiente imagen, el siguiente paso es pasar a Excel para escribir el código VBA.

Código XML con las llamadas a los Procedimientos de VBA.


Antes de continuar leyendo el artículo recuerda que todo lo que os ofrezco aquí es Gratis, pero si te gusta mi trabajo, puedes realizar una donación para que pueda continuar con este proyecto. Cualquier cantidad desde 1€/1$ es bienvenida. Gracias!!!!!!!!!!!!!!


Ahora nos vamos a Excel, en mi caso a Excel 2013 y abrimos el documento. Si no hemos cometido errores se abrirá con la ficha personalizada en primer lugar. Ahora debemos crear el código VB, para escribirlo debemos acceder al Editor de Visual Basic. Podéis acceder a él pulsando el botón "Visual Basic" situado en la ficha "Desarrollador" o pulsando las teclas "Alt+F11".

Botón Visual Basic de la ficha Desarrollador
Botón Visual Basic de la ficha Desarrollador.

Editor de Visual Basic en Excel 2013
Editor de Visual Basic en Excel 2013.

Una vez estamos en el editor el primer paso es crear el módulo que contendrá los dos procedimientos de código VB que necesitamos para nuestros botones. Hay diferentes maneras de organizar el código VB y una de ellas son los módulos, son contenedores de código que puede ser llamada desde otros sitios, en este caso desde unos botones de la Cinta de Opciones. Para insertar el módulo, accedéis al menú "Insertar" y seleccionáis la opción "Módulo".

Creamos un Módulo en el menú Insertar
Creamos un Módulo en el menú Insertar.
Módulo de Visual Basic creado
Módulo de Visual Basic creado.

Al seleccionar esa opción se creará un módulo de VB en blanco listo para escribir el código que se ejecutará al pulsar los botones. En la parte izquierda de la ventana podéis ver el módulo insertado llamado "Módulo1", ahora le cambiaremos el nombre. Y en la parte de la derecha podéis ver una ventana en blanco que es donde escribiremos el código. Abajo a la izquierda, tenemos la Ventana de Propiedades, ahí es donde le vamos a cambiar el nombre, recordad que el código que se ejecutará al pulsar los botones debe estar en un módulo llamado "Facturas".

Cambiamos el nombre del Módulo en la ventana de Propiedades
Cambiamos el nombre del Módulo en la ventana de Propiedades.

Ahora llega el momento de escribir el código VB, vamos con el procedimiento para el primer botón.

Public Sub CrearFactura(Control As IRibbonControl)
    Worksheets.Add After:=Worksheets(Worksheets.Count)
End Sub

Como ya os he dicho he simplificado mucho los ejemplos y estas líneas lo único que hacen es crear nuevas hojas en el documento. Si habéis escrito bien el código y probáis el botón, veréis que va insertando una hoja nueva, justo después de las existentes.

Cada vez que pulsamos el botón inserta una hoja nueva al final
Cada vez que pulsamos el botón inserta una hoja nueva al final.

Vamos con la explicación del código, para empezar la primera línea. En esa línea definimos un procedimiento público, un código que puede ser llamado y ejecutado desde cualquier parte del documento en el que estamos trabajando, en este caso desde el primer botón de la ficha "Facturación". La instrucción que define el procedimiento es "Sub" y el "Public" indica lo que os acabo de decir, que puede ser llamado desde cualquier sitio. Después de Sub aparece el nombre del procedimiento "CrearFactura", que evidentemente coincide con el que habíamos indicado en el código XML. Si nos confundimos y le damos otro nombre fallará, nos dará un mensaje como el siguiente.

Error por no encontrar el procedimiento indicado en el código XML
Error por no encontrar el procedimiento indicado en el código XML.

En el mensaje nos dice que no encuentra la macro, en este caso porque nos hemos confundido en el código VBA al dar el nombre. Seguimos con esa primera línea de código que es corta pero tiene mucho que comentar. Entre los paréntesis de definición del procedimiento hemos indicado un argumento del tipo "IRibbonControl". Este argumento es obligatorio ponerlo, si no lo hacéis fallará el código, ojo porque se suele olvidar mucho. En nuestro caso no lo usamos para nada, pero los procedimientos que son llamados desde "onAction" de un botón tienen la obligación de llevarlo. Este no es el caso, pero si necesitará saber cuál ha sido el botón pulsado, podría saberlo a través de ese argumento. De momento quedaros con que es obligatorio ponerlo y más adelante ya os pondré un ejemplo de para que podría ser útil. Si no lo ponéis recibiréis un error como el siguiente.

Public Sub CrearFactura()

Error por no poner el argumento de tipo IRibbonControl.

En el mensaje ya veis que habla de número incorrecto de argumentos, esto es porque falta el argumento que debía poner entre los paréntesis. Seguimos con la segunda, esta línea en realidad no es importante para el tema del artículo, ya que no es algo específico de la programación de la Ribbon. Lo "único" que hace es añadir una hoja nueva y situarla la última. "Worksheets" es una colección de objetos que representa a todas las hojas de trabajo del documento, las hojas con celdas. "Add" es un método que permite añadir hojas y cada vez que se ejecuta añade una hoja. Este método tienen un argumento llamado "After" que nos permite indicar detrás de que hoja queremos crear la nueva hoja, en este caso le decimos que justo después de la  última. "Count" es una propiedad de "Worksheets" que devuelve el número de hojas de trabajo que contiene un documento, ese número lo utilizo para indicarle detrás de que hoja tiene que crear la nueva. Eso es a grandes rasgos lo que hace esa línea.

Por acabar ya con este código, la tercera línea simplemente finaliza el procedimiento. La definición de un procedimiento empieza por la palabra "Sub" y acaba con "End Sub". En realidad el "Public" no hace falta ponerlo, si no lo hacéis el procedimiento sería público por defecto, luego da igual ponerlo. Bueno pues este botón ya está, vamos con el código para el otro botón. Esto botón debía borrar la hoja en la que estamos en ese momento.

Public Sub EliminarFactura(Control As IRibbonControl)
    Application.DisplayAlerts = False
    ActiveSheet.Delete
    Application.DisplayAlerts = True
End Sub

En estas líneas, en cuanto a lo que está relacionado con el botón y el XML, no hay nada nuevo. El procedimiento se llama tal y como hemos indicado en el código XML y recibe el mismo argumento que hemos indicado antes, que como hemos dicho es obligatorio. En cuanto al código para borrar la hoja, la línea que realmente borra la hoja es la tercera, en la que usamos el método "Delete". En ella le indicamos que borre la hoja activa, "ActiveSheet" representa a la hoja en la que estamos en ese momento. Las otras dos líneas sirven para evitar que aparezca este mensaje.

Confirmación para eliminar una hoja de Excel
Confirmación para eliminar una hoja de Excel.

Con esas dos líneas lo que hacemos es desactivar los mensajes de confirmación que puede mostrar Excel en determinadas circunstancias, por ejemplo al eliminar una hoja. Cuidado porque es muy peligros hacer esto, eliminar sin pedir confirmación es muy peligroso. "Application" representa a Excel y esta tiene una propiedad que permite desactivar o activar este tipo de confirmaciones. Asignando el valor "False" las desactivamos y asignando el valor "True" las activamos. Lo que hago aquí es desactivarlas justo antes de eliminar la hoja y activarlas de nuevo justo después de la eliminación. Ya os digo que cuidado con esto, os lo explico para que conozcáis pequeños trucos de la programación con VBA. Si probáis el botón eliminar veréis que elimina la hoja en la que estáis en ese momento. Si vais borrando todas las hojas e intentáis borrar la última, os dará un error. Un libro debe tener por lo menos una hoja y no os dejará eliminar la última que quede.

Error al intentar eliminar la última hoja del documento
Error al intentar eliminar la última hoja del documento.

Por acabar ya, a continuación os dejo una imagen de cómo debería quedar el editor con todo el código escrito.

Codigo VBA final
Código VBA final.

Bueno, pues ya está, ya tenemos conectados los dos botones de la Cinta de Opciones con el código VB que debían ejecutar. Lo "único" que hay que hacer es indicar en la propiedad "onAction" el procedimiento que queremos ejecutar... Y después en el editor debemos tener en cuenta que ese procedimiento tiene que cumplir una estructura, debe tener un argumento de tipo "IRibbonControl" en su definición. Parece mucho trabajo para lo que conseguimos, pero es que esto sólo es un 1% de lo que se puede llegar a crear y personalizar la Interface de Excel. En los próximos artículos más ;)

*Siguiente Artículo:*:

10 comentarios:

  1. Excelente de nuevo. Estoy siguiendote paso a paso, ya que utilizo mucho VBA y quisiera conocer más de esta vinculación con XML, y si es necesario también aprenderlo.

    Saludos. Gracias.

    ResponderEliminar
    Respuestas
    1. De nada!!!!!!!!!!

      Poco a poco iremos usando más VBA.

      Saludos.

      Eliminar
  2. hola, muy interesante!!! he tratado de seguir tus videos paso a paso y he conseguido aprender algo, solo que ahora me tope con algo que no puedo resolver, no puedo asignar una macro que no esta en el libro que estoy personalizando, solo me deja asignar macros guardadas en el libro, no es posible esto??

    saludos y te agradezco de antemano tu respuesta

    ResponderEliminar
    Respuestas
    1. Tendría que probar, pero porque quieres ejecutar macros de otro libro????

      Saludos.

      Eliminar
  3. buen dia
    tengo una pregunta
    puedo asociar una macro ya realizada a el botton de la ribbon
    ya que tengo mis macro ya realizadas pero quier asocialas a los botones de la cinta de opciones de la ribbon

    ResponderEliminar
  4. buen dia
    tengo una pregunta
    puedo asociar una macro ya realizada a el botton de la ribbon
    ya que tengo mis macro ya realizadas pero quier asocialas a los botones de la cinta de opciones de la ribbon

    ResponderEliminar
    Respuestas
    1. Si que puedes, pon el nombre de la macro en la propiedad OnAction y en la definición de la macro no se te debe olvidar poner esto entre los paréntesis:

      Control As IRibbonControl

      Eliminar
  5. Buena tarde Isacc Gomez, claro que si puedes asociar tus macros ya realizadas, lo unico que debes hacer es colocarla en la propiedad onAction y listo

    ResponderEliminar
  6. Buenas tardes, antes que nada un buen aporte el que haces. Tengo una duda, que pasa si mi función o sub procedimiento requiere de parámetros. Cómo hago para llamarlo desde el Ribbon y pasar los parámetros?.

    ResponderEliminar
  7. Excelente estos tutoriales del xml para la ribbon, gracias por el conocimiento compartido!
    Un Abrazo!!

    ResponderEliminar