martes, 14 de octubre de 2014

Artículo: Cómo Activar y Desactivar Botones en la Cinta de Opciones de Excel con enabled y getEnabled. 1ª Parte.

Botón desactivado en la Cinta de Opciones.
Botón desactivado en la Cinta de Opciones.
Seguimos profundizando en la personalización de la "Cinta de Opciones" de "Excel" y en este artículo os voy a explicar cómo activar y desactivar los botones que creemos en ella. Os voy a explicar cómo hacerlo tanto en tiempo de diseño como en tiempo de ejecución. Empezaremos el artículo hablando de la propiedad "enabled" que nos permite indicar si un control aparece activado o desactivado. Esta opción es interesante si por ejemplo queremos que los controles aparezcan siempre de inicio desactivados. Esta sería la opción que tenemos para controlar el estado de los botones en tiempo de diseño, cuando estamos creando el código XML que define el botón. Pero no es la opción más interesante y potente que tenemos para activar o desactivar controles. La otra posibilidad que tenemos es la de activar o desactivar los botones mientras se usan los documentos de Excel. Es decir dependiendo de condiciones que nosotros necesitemos controlar, decidiremos si los controles se activan o se desactivan. Para esto usaremos la función "getEnabled" y código VBA. El uso de esta función os lo voy a explicar en dos artículos, si lo haría todo en este quedaría un artículo muy largo y creo que así se entenderá mejor ya que su uso es un poco "extraño". Cuando empecemos con esta función os daré más detalles.

Para seguir los pasos de este artículo necesitáis descargaros el siguiente documento de Excel que he preparado. Es una modificación de los que he usado en artículos anteriores y en los vídeos que estoy publicando del mismo tema. Cuando lo tengáis lo abrís en el "Custom UI Editor".


Este documento tiene una ficha personalizada llamada "FACTURACIÓN" en la que hay tres botones, pero de entada ya os digo que sólo funciona uno, el botón para eliminar facturas. La idea es que con esos botones podemos crear, guardar y eliminar facturas pero los dos primeros botones tienen mucho trabajo y voy a dejar la explicación para los vídeos. Aquí me voy a centrar sólo en la parte importante, en cómo podemos activar o desactivar botones de la Ribbon. Para la primera parte de este artículo usaré el botón de crear nuevas facturas y para la segunda utilizaré el de eliminar facturas.

Botones personalizados de la Ribbon con los que vamos a trabajar.
Botones personalizados de la Ribbon con los que vamos a trabajar.

Vamos con la parte del artículo en la que os hablo de la propiedad o atributo "enabled". Esta propiedad también la tienen otros controles pero de momento en el curso estamos centrados en los botones que son los controles más sencillos de usar. La propiedad "enabled" establece si el control, en este caso el botón, está activado o no. Se le pueden asignar dos valores a esta propiedad, "true" o "false", verdadero o falso. Con true se activa el botón y con false de desactiva. Por ejemplo vamos a desactivar el primer botón que tenemos definido en nuestra ficha personalizada, el de crear nuevas facturas. Añadimos a la definición de ese botón esa propiedad.

<button id="botonNuevaFactura" label="Nueva" size="large" image="Nueva" enabled="false"/>

Igual que con el resto de propiedades escribimos el nombre de la propiedad y entre comillas dobles le asignamos su valor, en este caso "false" para desactivar el botón. Vamos a probar que hemos conseguido con esto, cerramos guardando los cambios y abrimos el documento en Excel. Al abrirlo, como lo habéis descargado de Internet seguramente os pedirá que habilitéis la edición y que habilitéis las macros, lo hacéis. Y como podemos ver en la siguiente imagen el botón aparecerá desactivado. Esta difuminado y si intentamos pulsar encima de él no podemos.

El primer botón de la ficha personalizada está desactivado con el atributo enabled.
El primer botón de la ficha personalizada está desactivado con el atributo enabled.

Bueno pues esta es la idea, con esa propiedad podemos establecer si un control está activado o no. Esto que os acabo de explicar está muy bien, lo que pasa que es muy limitado. Esto nos puede servir si queremos que algún control esté siempre desactivado al abrir un documento, pero si necesitamos que el botón este activado o desactivado dependiendo de algo, no lo podemos hacer con "enabled". Eso lo tendríamos que hacer con la función "getEnabled", vamos con ella.


El documento que habéis descargado tiene cuatro hojas. La primera es la plantilla de la factura que se usa para ir creando facturas y las otras tres son facturas ya guardadas. Mi idea es que con el botón de eliminar se puedan eliminar facturas guardadas, más concretamente lo que quiero es que elimine la factura en la que estoy situado en el momento de pulsar el botón.

Facturas guardadas que se podrán eliminar con el botón Eliminar.
Facturas guardadas que se podrán eliminar con el botón Eliminar.

Como no quiero que se elimine la plantilla de la factura, quiero que el botón de eliminar este sólo activado cuando estamos en una factura guardada. Si estamos en la primera hoja, en la plantilla de la factura quiero que se desactive. Esa es la idea, activar el botón eliminar sólo cuando esté en una hoja con una factura guardada y cuando esté en la de la plantilla lo quiero desactivar. Para conseguir esto no queda más remedio que usar la función "getEnabled".

Botón desactivado al situarnos en la plantilla de la Factura.
Botón desactivado al situarnos en la plantilla de la Factura.

Esta parte del artículo es la que os he dicho al principio que la iba a dividir y aquí os voy a explicar una parte el resto lo dejo para el siguiente artículo, creo que así es mejor. La voy a dividir en las siguientes dos situaciones, en este artículo os voy a explicar la primera. Para conseguir que todo funciones como yo quiero hay que pensar en estas dos situaciones. Cuando cerramos un documento en Excel y guardamos los cambios antes de cerrarlo, al abrirlo de nuevo, Excel recuerda en que hoja estábamos. Es decir si nos situamos en una de las hojas que contienen facturas guardadas, guardamos el documento y a continuación lo cerramos... Al abrirlo de nuevo apareceremos en esa factura otra vez. ¿Por qué es importante esto? Bueno pues porque si al abrir el documento aparecemos en la hoja de la plantilla, el botón debería aparecer desactivado para no permitir la eliminación de la plantilla que usamos para crear facturas. Y si por el contrario aparecemos en una factura guardada, el botón debería aparecer activado. Esta situación es la que os voy a explicar en este artículo.

La otra sería que cuando cambiamos de una hoja a otra, controlemos en que hoja nos situamos... Si acabamos en la hoja de la plantilla deberiamos desactivar el botón y si por el contrario acabamos en una hoja de una factura guardada, deberíamos activarlo. Esto es lo que vamos a dejar para el siguiente artículo. El acceso a la "Ribbon" desde VBA es algo complejo y creo que dividiendo esta parte en dos, lo entenderéis mucho mejor.

Bueno, vamos con el trabajo que va ser largo y "tortuoso", la verdad es que es sorprendente la de vueltas que hay que dar para trabajar con la "Ribbon" desde VBA. El que espere algo tan sencillo como "botonEliminar.Enabled = False", que se olvide. Vais a ver que es mucho más largo y complicado que eso.  Entonces, ahora nos vamos a preocupar de que al abrir el documento de Excel, el botón se active o se desactive dependiendo de la hoja en la que nos situemos nada más abrir el documento. La primera parte del trabajo la tenemos que hacer en el "Custom UI Editor", abrimos el documento en él y os cuento que hacemos. Para empezar añadimos al botón que elimina las facturas la propiedad "getEnabled", lo escribimos y ahora os cuento que significa lo que ponemos:

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

La parte nueva en esta línea es el uso de "getEnabled", ¿Qué es "getEnabled"? Bueno pues una propiedad de los controles que nos permite indicar una macro, un procedimiento de VBA que se encargará de decidir el estado del botón, si aparece activado o desactivado. La idea es que en lugar de usar la propiedad "enabled" para indicar un estado fijo, con una macro decidiremos cual es el estado del botón dependiendo de las condiciones que nosotros indiquemos. De hecho no se pueden usar las dos cosas juntas, si intentáis usar "enabled" y "getEnabled" en un mismo control, recibiréis un mensaje como el siguiente.

Los atributos enabled y getEnabled son incompatibles.
Los atributos enabled y getEnabled son incompatibles.

En él, básicamente nos dice que usemos una de las dos propiedades, las dos a la vez no. En un principio "getEnabled" sólo la vamos a usar para decidir cuál es el estado del botón nada más abrir el documento, pero como veremos en el siguiente artículo, parte de lo que estamos haciendo aquí, también sirve para establecer el estado del botón mientras estamos usando el documento. En esta ocasión le hemos indicado que para establecer el estado del botón debe usar una macro o procedimiento llamado "ActivarDesactivarBotonEliminar", situado en un módulo de código llamado "ModuloRibbon".

Como os podéis imaginar, la siguiente parte del trabajo es crear ese módulo y ese procedimiento. Cerramos el "Custom UI Editor" guardando los cambios y abrimos el documento en Excel. Al abrirlo recibiremos el siguiente mensaje de error:

Error por no encontrar la macro que hemos indicado en getEnabled.
Error por no encontrar la macro que hemos indicado en getEnabled.

Excel, al abrir el documento ha intentado establecer el estado del botón para eliminar facturas y como todavía no hemos creado la macro encargada de ese trabajo, nos muestra este mensaje en el que nos dice que no ha encontrado la macro o que puede que estén deshabilitadas. En este caso es que no está, la macro que llama la función "getEnabled" no existe. Aceptamos el mensaje y fijaros que el botón se queda desactivado, no ha sido capaz de decidir cómo debía estar y lo ha desactivado.

Botón desactivado porque no encuentra la macro que se llama desde getEnabled.
Botón desactivado porque no encuentra la macro que se llama desde getEnabled.

Vamos a crear la macro, accedemos al Editor de VB pulsando en el botón "Visual Basic" de la ficha "Desarrollador" y empezamos con el trabajo de programación.

Botón Visual Basic para entrar al Editor de Visual Basic.
Botón Visual Basic para entrar al Editor de Visual Basic.

Al entrar nos encontraremos con trabajo realizado en artículos anteriores, en concreto un módulo llamado "ModuloFacturas" en el que está el código que se encarga de eliminar las hojas. En realidad ese código borra cualquier hoja, pero como vamos a desactivar el botón cuando nos situemos en la hoja de la plantilla, en la práctica sólo borrará facturas guardadas.

Código desarrollado en artículos anteriores que elimina hojas de Excel.
Código desarrollado en artículos anteriores que elimina hojas de Excel.

El primer paso va ser crear otro módulo que contendrá la nueva macro o procedimiento. Lo podíamos haber creado en el que ya tenemos, pero por mantener un poco de orden lo vamos a meter en otro nuevo. Igual que hicimos en un artículo anterior, creamos el módulo en el menú "Insertar" y le cambiamos el nombre para que se llame "ModuloRibbon".

Creamos el módulo y le cambiamos el nombre.
Creamos el módulo y le cambiamos el nombre.

Y ahora dentro de este módulo creamos la macro que se encargará de establecer el estado del botón para eliminar facturas:

Public Sub ActivarDesactivarBotonEliminar(Control As IRibbonControl, ByRef Enabled)
End Sub

De momento aquí tenemos la definición de la macro, del procedimiento, hay varias cosas para comentar. Para empezar hemos indicado el mismo nombre que le habíamos dicho en el código "XML", si no, seguiría sin encontrarla. A continuación del nombre entre los paréntesis hemos indicado que este procedimiento recibe dos argumentos, son argumentos obligatorios. Las macros que se llamen desde "getEnabled" deben tener esos dos argumentos obligatoriamente. El primero nos serviría para saber desde que control se ha llamado a esta macro, pero en nuestro caso nos da igual. Este argumento puede ser interesante si a esta macro se le llama desde diferentes controles, desde diferentes botones, pero no es el caso. En nuestro caso el argumento realmente interesante es el segundo.

Con el argumento "Enabled" podremos acceder a la propiedad o atributo "enabled" del botón que llama a este macro. Ese argumento será la vía que vamos a tener para establecer el estado del botón. Fijaros que delante de ese argumento está la palabra "ByRef", esto indica que si modificamos el valor de ese argumento, en realidad estaremos modificando el valor de algo que está en otro sitio, en este caso el valor de la propiedad "enabled" del botón que llama a esta macro. Esto es como una especie de "puntero", pero este no es el sitio para liarnos ahora a hablar de "punteros". Quedaros con que modificando el valor de ese argumento, en realidad estamos modificando el valor de algo que está en otro sitio. Es un argumento que nos permite acceder a algo situado en otro sitio, en este caso a una propiedad de un botón situado en la Ribbon. Seguro que estáis diciendo, vale pero para que lo quiero... Bueno pues ahora llega esa parte, dentro de las dos líneas que acabamos de crear, escribimos lo siguiente.

If ActiveSheet.Name = "Factura" Then
    Enabled = False
Else
    Enabled = True
End If

Código completo de la macro que llama getEnabled.
Código completo de la macro que llama getEnabled.

¿Qué tenemos aquí? Bueno pues a primera vista algo muy sencillo, un condicional, un "If" con el que controlamos el nombre de la hoja en la que estamos situados ahora mismo. Recordar lo siguiente, esta macro la primera vez que se ejecuta es al abrir el documento. En el código XML le hemos indicado que para establecer el estado del botón que elimina facturas, debía llamar a esta macro... Y Excel, al abrir un documento y encontrarse con eso, la llama. Por lo tanto cuando pase eso, con este condicional, controlamos en que hoja del libro nos encontramos situados. Si la hoja en la que estamos se llama "Factura", si es la plantilla, le decimos que desactive el botón. Y como hacemos eso, bueno pues asignando al argumento "Enabled" el valor "False" y así lo desactivamos. Si la hoja activa en ese momento no se llama "Factura", a ese argumento le asigna el valor "True" para que el botón se active. Como os he comentado hace un momento, con ese argumento accedemos a algo que está en otro sitio, a la propiedad "enabled" del botón que llamaba a esta macro y modificando el argumento modificamos esa propiedad. En realidad esto es equivalente a lo que hacíamos al principio del artículo usando la propiedad "enabled" en el código XML, pero hecho desde Visual Basic.

Bueno vamos a probar, primero vamos a probar que pasa si cerramos el documento situados en una hoja de una factura guardada. Nos situamos en una de ellas, guardamos el documento, lo cerramos y lo abrimos de nuevo. En la siguiente imagen podéis ver todo el proceso.

Comprobación de la activación del botón para eliminar.
Comprobación de la activación del botón para eliminar.

Bueno, pues como podéis comprobar ha funcionado. Al abrir el documento, Excel llama desde "getEnabled" a la macro que hemos creado... Y como al abrirlo estamos situados en una hoja de una factura guardada, el botón aparece habilitado. Vamos a probar la otra situación, nos situamos en la hoja "Factura", guardamos los cambios, cerramos el documento y lo abrimos de nuevo.

Comprobación de la desactivación del botón.
Comprobación de la desactivación del botón.

Y como podéis comprobar funciona perfectamente. Al abrir el documento como estamos situados en la hoja "Factura", que es la que no queremos eliminar, el botón aparece desactivado. Por lo tanto ya está, ya hemos conseguido lo que queríamos. Cuando abrimos el documento y se carga la personalización de la Ribbon, a través de la función "getEnabled" se llama a esta macro que acabamos de desarrollar para establecer el estado del botón. Esto que hemos hecho también es cambiar el estado de los botones en tiempo de ejecución, lo cambiamos al abrir el documento que también se considera tiempo de ejecución, tiempo de uso del documento. Pero todavía nos queda lo más interesante, conseguir que se cambie mientras estamos trabajando en el documento, que también será tiempo de ejecución, tiempo de uso. Esto lo veremos en el siguiente artículo, parte del trabajo ya lo tenemos hecho, pero hay mucho más por explicar. Por hoy ya vale, hasta el siguiente artículo ;)

*Siguiente Artículo:*:

5 comentarios:

  1. buenos días David
    he seguido con mucho interés tus vídeos y artículos sobre la personalización de la cinta de opciones de Excel
    estoy aplicando alguno de los recursos que indicas y me he atascado en lo siguiente:
    tengo un botón personalizado en la Pestaña "Inicio" y después del Grupo "Modificar" que activa una macro. La personalización está hecha desde el menú opciones/personalizar cinta de opciones
    el botón se muestra en todos y cada uno de los libros que abro y la macro asociada es de uso habitual
    estoy intentando crear un libro que tenga otro botón en la misma Pestaña y en, más o menos, la misma posición que sea visible SÓLO en ese libro. esto lo he conseguido gracias a tus explicaciones pero lo que necesito saber es cómo hacer invisible o desactivar el botón genérico que aparece en todos los libros para evitar que por error se pudiese activar
    todas las pestañas y botones estándar los puedo ocultar/desactivar porque tienen su identificador único
    creo que sabría hacerlo pero mi problema es que no sé cómo identificar el ID del botón genérico ni sé si hay alguna otra forma de identificarlo para poder ocultarlo o desactivarlo para un libro determinado
    tengo Excel 2010 y NO dispongo del Custom UI Editor porque el ordenador es el de mi trabajo y no se permite descargar ningún tipo de software
    muchísimas gracias por tu tiempo
    saludos

    ResponderEliminar
  2. Pues la verdad es que no te puede ayudar ahora mismo. Desconozco si hay alguna manera de acceder al ID de un botón creado de esa manera.

    Si tengo tiempo... intentaré mirarlo, pro así de primeras no lo sé.

    Saludos.

    ResponderEliminar
    Respuestas
    1. buenos días David
      He avanzado un poco, pero sólo un poco
      Quizás la siguiente información te sirva
      Las pestañas que se crean a través de Archivo/Opciones/Personalizar cinta de opciones dejan una “huella” en la siguiente ruta: C/Usuarios/tu_usuario/AppData/Local/Microsoft/Office/Excel.officeUI
      Imagino que la ruta podrá variar según el ordenador de cada cual
      Al abrir el Excel.officeUI aparecen todas las personalizaciones que se tengan en tu Excel (Barra de opciones de acceso rápido, pestañas…)
      En mi caso, mi pestaña personalizada aparece tanto un id del tipo “id=mso_c1.B7AB01” junto con su label, su imageMso, y dentro de la pestaña un button con un idQ=”x1:C-Users_miusuario_Appdata_Roaming_Microsoft_Excel_XLSTART_PERSONAL.XLSB_nombre de mi macro_0_447F9” con su label, su imageMso, y su onAction correspondientes
      Todo induce a pensar que el Id de mi pestaña personalizada sería equivalente al Id de las pestañas predefinidas de Excel como el TabHome, el TabInsert, etc y que, por lo tanto, puedo manejar aquella igual que puedo estos, por ejemplo, para hacerlos invisibles o desactivarlos
      He hecho muchísimas pruebas y no lo consigo; sólo lo oculto si oculto todo el ribbon con la instrucción
      Espero que esta información te ayude a ayudarme
      Muchísimas gracias
      Saludos
      Manuel

      Eliminar
  3. perdon, he olvidado añadir la intrucción con la que oculto todo el libro
    la instrucción es "ribbon startFromScratch="true""

    ResponderEliminar
  4. Por favor, como debo hacer para que cuando abra el archivo, una vez, ya tenga el menú Ribbon como por ejemplo "Facturación",se active la pestana o ficha o tab "Facturación" y aparezcan las opciones de Facturación?
    Muchas gracias
    jflav@ibersur.es

    ResponderEliminar