Uso de macros desde script (2)
La esencia de este procedimiento es la misma que la vista en la entrada anterior, pero la diferencia es que ahora los script son más genuinamente tales, esto es: en ellos se hace uso de los elementos del lenguaje (OOo Basic, en nuestro caso), lo que permite un mejor aprovechamiento de las propias macros y, sobre todo, un funcionamiento más funcional a la vez que complejo del algoritmo.
Este modo de trabajo supone, incluso, recurrir a OOo Basic para realizar ciertas modificaciones en las propias macros. Aunque esto no obligatorio (podemos seguir trabajando con las macros tal y como "salen del horno" de Grabar macro), hacerlo mejora sustancialmente la propia funcionalidad de la macro, por lo que es muy recomendable.
Lo que pretendemos ahora es dar más flexibilidad al conjunto (también a las macros), apoyándonos en los elementos del lenguaje OOo Basic y en lo conocemos de su sintaxis. Todo ello lo encontraremos en el
contenido de esta página, como sabes.
Por comodidad y coherencia, partiré del conjunto de macros creados con motivo de la entrada anterior (1), incluyendo una macro simple de escritura para dar más funcionalidad a los script. Podríamos partir de un conjunto de macros simples diferentes, pero para nuestro objetivo, más que suficiente, es conveniente utilizar las anteriores macros.
Lo primero que vamos a hacer (2), es simplificar el código de las macros, aprovechando lo que sabemos sobre el uso de variables públicas y privadas. Como ves, al inicio de cada macro, Grabar macro genera un código básico que se repite en todas las macros, y en la misma posición. Estas líneas de código son las que llaman a dos objetos básicos para el funcionamiento de la macro: el documento activo y la funcionalidad lanzador de macro ("com.sun.star.frame.DispatchHelper") que Grabar macro almacena en dos variables que llamaré de sistema: document y dispatcher.
Este código repetido en cada macro es el siguiente:
rem get access to the document
document = ThisComponent.CurrentController.Frame
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")
Y como se repite siempre que creamos una macro, podemos considerar estas dos variables como públicas, por lo que las declararemos al inicio del módulo, fuera de las macros, para que sean accesibles a todas ellas y crearemos un script (sub VarSis) específico (3) con la asignación de los objetos a las variables. Esto se concreta en el código siguiente:
'Declaración de variables de sistema para macros
dim document as object
dim dispatcher as object
'Subrutina de asignación de objetos a las variables de sistema para macros
Sub VarSis
document = ThisComponent.CurrentController.Frame
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")
Ahora ya podemos simplificar y reducir la extensión del código, eliminando esos elementos de cada macro y sustituyéndolos por una llamada a VarSis (4) como, por ejemplo (5):
dispatcher.executeDispatch(document, ".uno:GoToStartOfDoc", "", 0, Array())
Aunque al ser la creación de macros un proceso automático, por lo que no tenemos que escribir nosotros ni una sola línea de código y, por ello, simplificar las macros (lo que acabamos de hacer) no nos ahorra tiempo; al contrario, supone un trabajo, sencillo, pero trabajo, sobre todo si las macros son muchas; recomiendo hacerlo por las ventajas que supone en términos de legibilidad y funcionalidad del código en su conjunto. De todas formas, si no lo hacemos no se va alterar el funcionamiento de las macros ni de los script que las empleen; se ahorra algo de tiempo de ejecución y de memoria RAM, pero resulta imperceptible, dada la velocidad de procesamiento y capacidad RAM de los ordenadores actuales.
Lo que ya no es opcional si queremos aprovechar los conocimientos que tenemos sobre el uso de OOo Basic es trabajar de forma que, integrando varias macros, podamos generar resultados que sin este uso de OOo Basic no lograríamos con macros o resultaría mucho más costoso. Además, en cuanto a lógica de programación es mucho más interesante crear este tipo de script que limitarse a llamar a macros.
Vamos a ver una de las formas de hacer uso de OOo Basic para crear un script que, basándose en macros y haciendo uso de variables y un ciclo, nos permita adaptar nuestro código de forma que resulte más útil e interesante.
- Primero. Modificamos la estructura de determinadas macros (en este caso las que vamos a usar) (6) transformándolas de hecho en subrutinas (tienen la misma estructura que una subrutina (7). Veamos un ejemplo:
sub LetraTipo (sLetraT As string)
dim args1(0) as new com.sun.star.beans.PropertyValue
dispatcher.executeDispatch(document, ".uno:"+sLetraT, "", 0, args1())
- Tras el nombre (LetraTipo) abro y cierro paréntesis y en su interior declaro la variable sLetraT como string: sub LetraTipo (sLetraT As string)
- En args1(0) sustituyo el dato original ("Bold") por la variable sLetraT: args1(0).Name = sLetraT. De este modo, en lugar de un valor fijo, puedo trabajar con los valores que asigne a la variable sLetraT.
- Procedo del mismo modo en el ejecutor o lanzador de la macro, sustituyendo el segundo argumento por una cadena de texto resultante de concatenar un texto fijo con la variable anterior. El resto de los argumentos no sufre variación: dispatcher.executeDispatch(document, ".uno:"+sLetraT, "", 0, args1()) (8)
Segundo. Creo un script en OOo Basic cuyo funcionamiento esperado es el siguiente:
- Se sitúa el curso al inicio del documento
- Se escribe una frase en negrita.
- Se produce un determinado número de saltos de línea
- Y se escribe una segunda frase también en negrita
Este script que contiene variables a las que se asignan valores; estas variables se pasan como argumentos a la hora de llamar a las macros-subrutinas, las cuales asumen la función de los argumentos que se declaran en dichas macros-subrutinas (ver Primero)
Para generar los saltos de línea se hace uso de un bucle For que se inicia en 0 y se repite tantas veces como el valor numérico que se asigne a iNumLineas (4 en nuestro caso). Tras este salto de línea se ejecuta de nuevo llamada a la macro-subrutina EscribirPalabra(), asignando previamente un string diferente a la variable sTexto (argumento de la macro-subrutina EscribirPalabra().
Podemos pensar en otras formas de utilizar macros como elementos de script; esta es una de ellas, pero no la única. Por ejemplo, siguiendo la misma línea de trabajo que hemos desarrollado en este script, podemos hacerlo interactivo, solicitando al usuario valores de entrada para crear otros texto. Para ello usaríamos la función InputBox(), por ejemplo. Pero lo hecho es suficiente para mostrar las posibilidades que tiene esta forma de hacer uso de la combinación de macros, macros convertidas en subrutinas y script.
Te dejo a continuación acceso al documento que contiene las macros y el script explicados en esta entrada.
NOTAS.
(1) Lo recomendable es ir creando macros simples, eso sí, adaptadas según se explicará en esta entrada, y guardarlas en el IDE en Mis macros y diálogos, para que sean accesibles desde cualquier script. Los script, por el contrario, posiblemente sea preferible almacenarlos en el propio documento, aunque no siempre, ya que depende del uso que se pueda hacer de ellos: si van a ser de uso frecuente en diferentes documentos, es preferible guardarlos también en Mis macros... Esta ubicación es muy recomendable (en esos casos) para el usuario que crea el código, pero imposibilita compartir con otras personas. En ese caso, se proporcionará el código por separado y será el usuario final quien decida donde lo copia y almacena.
(2) En realidad es lo segundo, ya que la primera acción debe ser (ahora ya muy recomendable) limpiar el código de las macros de código basura, tal y como se explicó en la entrada anterior.
(3) Este script de asignación puede tener cualquier otro nombre que deseemos darle, no necesariamente VarSis. Eso queda a elección del programador, pero, obviamente, la llamada que después debemos realizar a ese script debe ser coherente con el nombre que le demos.
(4) Observa que no necesario utilizar la expresión Call para llamar al script. es suficiente con escribir el nombre del script para que sea llamado. No obstante, el uso de Call facilita la lectura del código ya que denota que se está llamando a una subrutina externa.
(5) En realidad no es necesario llamar a VarSis desde cada macro, es suficiente con llamar a este script desde el script con que queramos manejar las macros. Sí es conveniente hacer incluir en las macros la llamada al script VarSis si queremos mantener la autonomía de cada macro, por si ocasionalmente necesitamos activarlas de forma directa (e individual), desde la funcionalidad Macros/Ejecutar macro del menú Herramientas.
(6) Los cambios de nombre que realizo respecto al original son para dar más coherencia al significado de las macros respecto a lo que hacen.
(7) Recuerda que en OOo Basic se diferencia entre subrutinas y funciones, pero en otros lenguajes (Python, por ejemplo) se llama función a ambas, diferenciándolas por su comportamiento: una subrutina realiza una acción y una función devuelve un dato. Esta denominación puede dar lugar a confusión, ya que, salvo que se especifique lo contrario, todos los script escritos en OOo Basic se inician por la expresión Sub, que deriva de Subroutine, que no necesita traducción.
(8) Esto último no es necesario hacerlo en todas las macros (ver, por ejemplo, la transformación de la macro EscribirPalabra en subrutina), pero sí en este caso, ya que el contenido de ese segundo argumento contenía originalmente el valor .Bold ( ".uno:Bold"), lo que genera ahora conflicto con el diseño subrutina de la macro. Esto no implica necesariamente que genere error, pero sí puede alterar el funcionamiento del script.