viernes, 26 de abril de 2024

OOo Basic. Datos

 Variables. Primeros pasos. (1)

Decía en una [entrada] que anterior que una macro creada con Grabar macro presenta una limitación insuperable en lo que toca a la personalización de los datos. Lo ejemplificaba con la personalización de un documento en términos de persona, lugar, fecha, área del currículo. En [otra entrada], de paso que aprendimos a identificar y usar variables, aprendimos también a superar esas limitaciones, precisamente usando variables. Este es el tema que ahora vamos a tratar en esta entrada y en las que la siguen.



Repito lo dicho: en programación, una variable no es un identificador de una dirección de memoria (RAM), un puntero que "apunta" a ese espacio de almacenamiento y, en consecuencia, al dato o datos que contiene.

Antes de hablar de los tipos de datos, recordemos las acciones previas que, de forma implícita o explícita, es necesario realizar para crear y dar funcionalidad a una variable.
  • En primer lugar deberemos declarar esa variable empleando en OOo Basic la expresión reservada Dim cuando lo hacemos de forma explícita.
  • En segundo lugar nombramos la variable, asignándole un nombre identificativo, respetando las reglas establecidas en el lenguaje. Es común el uso de expresiones alfanuméricas, lo más descriptivas posible. 
    • Se pueden nombrar como se desee, siempre que no sean palabras reservadas y no se inicie con símbolos coincidentes con los empleados como conectores o como  operadores.
    • Se recomienda iniciar con la inicial identificadora del tipo de variable en minúscula, bien en castellano (tNombre) o en inglés (sNombre), ambas para identificar una variable de tipo texto (string) destinada a la asignación del nombre del sujeto. 
    • Este modo facilita la identificación del tipo de variable, pero no implica la categorización tipológica.
En caso de que esa descripción implique el uso de varias palabras hay que recordar que deben ir juntas. En ese caso se utilizan dos procedimientos:
    • Unirlas mediante guion bajo (Var_Primera)
    • O escribirlo todo junto, poniendo en mayúscula la primera letra de cada palabra (VarPrimera)
  • En tercer lugar asignamos tipología mediante la expresión As Tipo (vg, As String, en el caso de sNombre)
  • Finalmente asignamos contenido (dato/s) a la variable, empleando para ello el operador de asignación, que en OOo Basic es el signo =
Ejemplificando el proceso explicado antes aplicándolo a la creación de una variable para contener el nombre de un alumno o alumna, el resultado sería el siguiente:

Dim sNombre As String (es equivalente dim sNombre as string)
sNombre = "Luis" (dado que se trata de una variable de tipo texto)

Cuando deseamos declarar varias variables del mismo tipo, podemos hacerlo en una misma línea:

Dim sNombre As String, sApellido1 As String, sApellido2 As String 

De lo visto hasta el momento se sigue lo que podemos llamar explicitación del proceso, pero cabe realizarlo de forma implícita. En OOo Basic ambas opciones están disponibles, aunque se recomienda utilizar la explícita por motivos de claridad de escritura del código.

De optar por esta alternativa es recomendable indicarlo mediante la expresión Option Explicit escrita antes de crear el primer script del módulo. De este modo se hace obligatoria la declaración y explicitación tipológica. En caso contrario, es suficiente con la asignación de datos para presuponer el proceso previo.

Como ejemplo aporto dos sencillos script (disponibles desde el IDE) [en este documento]. El primero funciona siempre que esté anulada (comentada) la expresión Option Explicit y el segundo funciona tanto si lo está como si está activa (no comentada).


NOTA

(1) Con fecha 26/04/2024 modifico la entrada original (12/06/2023) para ajustarla a la reformulación del esquema de contenidos actual de la página (apartado del blog) OOo Basic. En la modificación se incluye información relativa a las entradas que anteceden a ésta y se mantiene el resto del contenido de la original.

OOo Basic

Variables

Una orientadora, Mercedes, está colaborando con la Jefa de estudios del colegio elaborando informes escolares de una lista de alumnos y alumnas (el motivo ahora no es relevante). Mercedes piensa usar lo que estamos aprendiendo sobre LibreOffice y piensa crear un documento-base en Writer para elaborar los informes que recojan los datos de ese análisis. Veamos cómo lo podemos enfocar.


Después de investigar unos cuantos expedientes y una vez que se hace idea de cómo abordar el tema, Mercedes se plantea crear un documento-modelo para recoger toda la información. Hace un informe a modo de "ejemplo" y, después de revisarlo y reajustarlo, se plantea utilizarlo como base para construir los restantes. 

Aunque una Mercedes real posiblemente actuara de otro modo (1), nosotros vamos a suponer que quiere poner en práctica lo aprendido hasta ahora: crear macros y script.

Puesta a la tarea, Mercedes crea una primera macro a la vez que va escribiendo su documento. Supongamos que este texto es parte del inicio del documento:

Juan es actualmente alumno de 4º de E. Primaria en el C.P. Aurelia Sánchez (Santullano)

Activa Grabar macro, escribe el texto, finaliza la grabación, prueba su macro y observa que funciona según lo previsto. Pero ahora se le presenta un dilema: si quiere hacer ahora el informe de Luis se encuentra conque o utiliza su documento como documento-base y sustituye Juan por Luis o tiene que crear una macro para cada alumno. Evidentemente esta segunda opción no es razonable, ya que no le quita trabajo (2).

Supongamos que, a pesar de ello, crea una segunda macro, ahora con este otro texto:

Luis es actualmente alumno de 2º de E. Primaria en el C.P. Aurelia Sánchez (Santullano)

Comparemos ambos textos:

  • Observamos que varían dos datos: el nombre del alumno y el curso.
  • El resto permanece igual
Esos datos que varían (Juan - Luis y 4º - 2º) son las variables. Ambos pertenecen a dos conjuntos, el conjunto nombre y el conjunto curso, por lo que podemos entender que una variable, además de lo obvio (un dato que varía) también se puede entender como la denominación genérica de un conjunto de datos.

Pero desde la perspectiva de la programación, una variable es, en realidad, un identificador de un espacio de memoria RAM a cuyo contenido se accede utilizando ese identificador.

En todo caso, y con independencia de con qué conceptualización nos quedemos, usar variables nos va a permitir resolver de forma sencilla el problema de Mercedes: es suficiente con que sustituya el nombre concreto por un identificador como sNombre y el curso por sCurso para que no necesite cambiar en el texto ni el nombre ni el curso. Pero aun no sabemos cómo se hace eso.

Vamos a ver qué dice las macros que ha creado Mercedes. Para ello accedemos al IDE como sigue: 
  • Herramientas | Macros  | Editar macros.
  • Si no estamos ya en nuestro documento, Biblioteca Standard, Módule1 (por ejemplo), repetimos la selección que implica llegar hasta aquí...
  • Y nos encontramos con el código siguiente:

sub InfoEscolar1
rem ----------------------------------------------------------------------
rem define variables
dim document   as object
dim dispatcher as object
rem ----------------------------------------------------------------------
rem get access to the document
document   = ThisComponent.CurrentController.Frame
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")

rem ----------------------------------------------------------------------
dim args1(0) as new com.sun.star.beans.PropertyValue
args1(0).Name = "Text"
args1(0).Value = "Juan es actualmente alumno de 4º de E. Primaria del C.P. Aurelia Sánchez (Santullano)"

dispatcher.executeDispatch(document, ".uno:InsertText", "", 0, args1())

end sub

sub InfoEscolar2
rem ----------------------------------------------------------------------
rem define variables
dim document   as object
dim dispatcher as object
rem ----------------------------------------------------------------------
rem get access to the document
document   = ThisComponent.CurrentController.Frame
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")

rem ----------------------------------------------------------------------
dim args1(0) as new com.sun.star.beans.PropertyValue
args1(0).Name = "Text"
args1(0).Value = "Luis es actualmente alumno de 2º de E. Primaria del C.P. Aurelia Sánchez (Santullano)"

dispatcher.executeDispatch(document, ".uno:InsertText", "", 0, args1())

end sub

Tenemos dos macros (Sub InfoEscolar1 y Sub InfoEscolar2) que son exactamente iguales, a excepción de la diferencia de nombre y curso que ya identificamos antes. Poca opción nos da esto para ahorrar tiempo. ¿Cómo podemos usar variables en este caso?.

Con el tiempo aprenderemos que una macro en realidad  hace uso de variables, pero por ahora las que emplea no nos resuelven el problema. Y esta es la principal limitación de las macros, motivo por el que necesitamos aprender a trabajar con OOo Basic, incluso para mejorar (y simplificar) el uso de macros.

Como ya sabemos crear un script en OOo Basic, en esta entrada vamos a avanzar lo suficiente para resolver el problema a Mercedes:
  • A continuación de la expresión dim dispatcher as object vamos a crear una línea en blanco (Intro) (en realidad dos líneas).
  • Y escribimos Dim sNombre As String en la primera y Dim sCurso As String en la segunda (3). Ya tenemos creadas nuestras variables.
  • A continuación buscamos línea...

args1(0).Value = "Juan es actualmente alumno de 4º de E. Primaria del C.P. Aurelia Sánchez (Santullano)"

  • Y sustituimos  "Juan es actualmente alumno de 4º de E. Primaria del C.P. Aurelia Sánchez (Santullano)" por sNombre & " es actualmente alumno de " & sCurso & " de E. Primaria del C.P. Aurelia Sánchez (Santullano)" (es importante respetar el uso de las comillas y los espacios iniciales)
Con esto la segunda macro ya no es necesaria, así que la podemos borrar.

Mercedes dispone ya de variables en sustitución de los datos (nombre y curso), pero aun no puede sacar todo el partido posible de su descubrimiento: necesita un medio para introducir los datos concretos (Juan y Luis, por ejemplo). Para ello tiene que aprender a dar valor (asignar contenido o datos) a las variables, para ello...
 usar una función OOo Basic llamada InputBox(), asociándola a cada una de sus variables. Vemos cómo.
  • A continuación de Dim sCurso As String generamos un salto de línea (mejor dos para que el código sea más visible) y escribimos estas dos líneas:

sNombre = "Juan"
sCurso = "4º" 

Con ellas estamos diciendo a OOo Basic que almacene en el espacio de memoria RAM identificado como sNombre el dato "Juan", de modo que cuando aparezca la expresión sNombre acceda a ese espacio de memoria, recupere su contenido (el dato "Juan" en este caso) y haga con él lo que corresponda (en nuestra "macro" escribir Juan antes de la cadena " es actualmente..."). Y lo mismo con sCurso.

Usar este procedimiento no es la mejor opción posible, ya que obliga a Mercedes a acceder al IDE y realizar las asignaciones pertinentes para cada informe, así que mejor buscamos otra solución más funcional: usaremos la función OOo Basic llamada InputBox(), asociándola a cada una de las variables. Vemos cómo:

  • Sustituimos  sNombre = "Juan" por sNombre = InputBox("Nombre del alumno"
  • Y hacemos lo mismo con sCurso
Ahora Mercedes ya no tiene que acceder al IDE, es suficiente escribir el nombre (y el curso) del alumno en espacio disponible en la ventanita emergente que genera la función InputBox() y que tendrá a su disposición de forma automática una vez que llame a la macro (Herramientas | Macros | Ejecutar macro)

Aunque parezca poco, en esta entrada hemos avanzado mucho:
  • Hemos accedido a una macro e identificado en ella la información que nos interesa.
  • Hemos aprendido a crear (declarar) y usar (asignar valor y sustituir el dato concreto por la variable) variables.
  • Y hemos automatizado y generalizado la creación de un documento combinando una macro con unas variables, lo que equivale a decir que hemos aprendido (de momento empezado a aprender) cómo superar las limitaciones de las macros mediante su tratamiento con OOo Basic.
  • Además hemos utilizado una función que facilita la fase Input del proceso básico de un script (Input - Procesamiento - Output) (4)
Evidentemente lo aprendido hasta ahora sobre las variables no es más que el principio, pero en las entradas que siguen seguiremos aprendiendo mucho más sobre ella. Por el momento te dejo para que descargues el documento [loPrimero.ods] con la macro modificada (InfoEscolar) según los pasos seguidos en esta entrada para que puedas estudiarla y crear tú las réplicas que te parezca (5).

NOTAS

(1) Una Mercedes real posiblemente se quedara aquí y se limitara a marcar los espacios de los datos que varían, manteniendo el resto del contenido, a modo de texto mutilado. No es mala opción y a la altura del proceso de aprendizaje en que nos movemos es posible que incluso sea la mejor opción. Excepción hecha del uso de la funcionalidad Combinar correspondencia, siempre que el documento no sea muy complejo. De todos modos (posiblemente sin saberlo) Mercedes está trabajando "manualmente" con variables (y constantes). No obstante nosotros vamos a darle más recorrido el tema y hacerlo un poco más complejo. Complicar lo sencillo es, a veces, una buena forma de aprender. 

(2) En realidad, aun en esta caricaturización de la situación crear una macro sí supone un ahorro de tiempo. Si el documento tiene cierta extensión, se aprecia la ventaja (relativa, pero real) que tiene Grabar macro: crear una macro que le dé forma y contenido evita tener que escribirlo todo desde cero. También es más estable, seguro y manejable que trabajar con un documento-modelo. Es necesario, eso sí, utilizar (por ejemplo) Editar | Buscar y reemplazar para ir modificando los datos que varíen (quedémonos con esto: datos que varían)

(3) También podemos escribir Dim sNombre As String, sCurso As String, pero por ahora nos interesa diferenciar ambas expresiones. Además seguramente habrás pensado que "alumno" no es un término correcto cuando tengamos que hacer el informe de Rosa, con lo que también podría ser considerada una variable. Pero, por didáctica nos limitaremos a las dos variables dichas.

(4) Como sin duda Mercedes es inteligente, se habrá dado cuenta además que, limpia de texto irrelevante, la sintaxis de la macro le permite crear todos los textos que se imagine, siendo suficiente con sustituir el párrafo de nuestra macro por cualquier otro texto, el cual puede haber creado previamente (copiar y pegar) o crearlo directamente sobre en el IDE. Esto incluye el uso de todas las variables que le interese. Sólo necesita copiar la macro, cambiar su nombre (Sub NuevoNombre) para no perder la macro original y realizar en args1(0).Value = a sustitución que propuse antes. Y todo ello sin necesidad de usar de nuevo Grabar macro. Eso sí que es un ahorro de tiempo.

(5) Para mayor claridad del ejemplo he borrado de la macro original todos los comentarios, que ahora son innecesarios, aunque es buena praxis comentar el código. Ya aprenderemos cómo. Originalmente esta macro se llamaba InfoEscolar1, pero como ahora no necesitamos crear una macro por cada informe que queramos crear, pasa a llamarse InfoEscolar.

OOo Basic

Primer script

En esta entrada vamos crear nuestro primer script con OOo Basic, el típico script con el que comienza toda andadura por el aprendizaje de los lenguajes de programación. Pero para ello deberemos saber dónde.


Al crear una macro nos hemos acercado al IDE, pero no terminamos de entrar en él porque no era necesario. Ahora sí.

El IDE (Entorno de Desarrollo Integrado) es la utilidad que nos permite trabajar con un lenguaje de programación. El ser OOo Basic un lenguaje de script interno y delimitado por la suite LibreOffice, su IDE se ubica y es accesible desde el propio entorno LibreOffice; desde la interface general y/o desde las interfaces de cada uno de sus servicios.

Nosotros vamos a trabajar (de momento) desde Writer, así que empezaremos creando un nuevo documento. Le daremos nombre (loDocumento1) y lo guardaremos en una carpeta que previamente habremos creado en nuestro Escritorio (1). De este modo empezaremos desde cero, que es la mejor forma de empezar.

Y lo haremos accediendo a Herramientas | Macros | Organizar macros | BASIC (2). Este es nuestro primer paso porque, al partir de un nuevo documento, como ya sabes, aun no se definido en él un espacio específico para nuestras macros y script.

En la ventana emergente hacemos clic (de nuevo) en Organizador y en la nueva ventanita seleccionamos el icono de nuestro documento (loPrimero.odt), en la crucecita que precede al nombre, y después en a que precede a la carpeta (Biblioteca) Standard  y hacemos clic en Nuevo (3). Surge una nueva ventanita que contiene un campo de texto con la palabra Module1 y tres botones: hacemos clic en Aceptar y automáticamente se crea Module1 dentro de Standard. Clic en Cerrar.

Si hacemos clic en Nuevo (ahora referido a macro/script, accederemos al contenido de las tres carpetas disponibles en el IDE: Mis macros y diálogos, Macros y diálogos de la aplicación y loPrimero.odt: ésta es la que nos interesa ahora. Seguimos el proceso ya conocido de selección y despliegue de componentes y terminamos accediendo a una pantalla  casi vacía: 

REM  *****  BASIC  *****

Sub Main

End Sub

Este será el "espacio" (documento) en el que crearemos nuestros script. Por el momento nuestro primer script, justo entre las instrucciones Sub Main y End Sub. Cuando finalicemos esto será lo que veamos:

Sub Main

    print "OOo Basic para orientadores"

End Sub

No es el típico saludo "Hola Mundo" pero cumple su misma función: anunciar(nos) que estamos empezando a aprender OOo Basic.

Ahora sitúa el cursos dentro del Sub y haz clic en la flechita verde situada encima de la palabra REM, o en Ejecutar | Ejecutar: obtendrás una ventana emergente que contiene la frase que hemos escrito. Este es nuestro primer script. Por ahora suficiente (4)



NOTA

(1) Es una sugerencia; tú puedes crearlo con el nombre que te parezca y guardarlo en donde creas oportuno. A tu cargo también la organización interna de esta carpeta y recordar dónde guardas tus archivos.

(2) Verás otras opciones de lenguajes, pero ahora no nos interesan, así que nos centramos en BASIC, que no es otra cosa que OOo Basic. Podemos nombrar nuestro módulo como deseemos, pero por ahora no nos vamos a detener en estos detalle, así que aceptaremos el nombre que se nos propone (Module1)

(3) Como vamos a crear un módulo, y es la opción por defecto, no me voy a referir ahora a las otras opciones (Diálogos y Bibliotecas)

(4) Cuando queras finalizar y acceder de nuevo al documento, sigue esta secuencia: Archivo | Guardar o Archivo | Cerrar. La segunda cierra el IDE sin guardar lo que hemos creado, así que te recomiendo que utilices la primera opción para no perder el trabajo realizado. Para finalizar del todo cerraremos nuestro documento loPrimero.odt de igual modo que cerramos cualquier otro documento Writer, guardando los cambios.

jueves, 25 de abril de 2024

OOo Basic

Primero, las macros.

El lenguaje OOo Basic se anuncia como lenguaje de macros, pero aunque esta consideración sea correcta en el sentido amplio que se da al término "macro", en sentido estricto y también práctico, puede dar lugar a confusión y conlleva un reduccionismo que afecta negativamente a la valoración de la potencialidad que tiene el conocimiento del lenguaje.




Por eso prefiero considerarlo simplemente como un lenguaje de programación orientado y delimitado a la creación de script dentro de la suite ofimática LibreOffice (1). De hecho uno puede trabajar con macros desde la funcionalidad Grabar macros y desconocer absolutamente OOo Basic, aunque lo que genera esa funcionalidad es precisamente una forma particular de código de este lenguaje.

El término "macro" es una simplificación de "macroinstrucción", que se puede entender como la ejecución unitaria y sucesiva de un conjunto de órdenes o instrucciones. Aunque también podemos entenderla instrumentalmente como lo que resulta de hacer uso de la funcionalidad Grabar macro

Es por eso considero que decir que OOo Basic es un  lenguaje de macros resulta insuficiente cuanto menos. 

Cierto es que el resultado de grabar una macro no deja de ser automatizar la ejecución de una serie de instrucciones que se presentan individualizadas e independientes cuando trabajamos directamente con el servicio (Writer, por ejemplo); pero OOo Basic es mucho más: permite hacer mucho más y resulta mucho más complejo, también útil y eficiente.

De hecho, mientras que para crear una macro no hace falta más que tener clara la secuencia de acciones que deseamos automatizar y activar la funcionalidad Grabar macro (2), crear un script, una subrutina o una función ni es posible desde Grabar macro ni se puede prescindir de conocer el lenguaje con el que se va a trabajar (en nuestro caso y como primera opción, OOo Basic).

Así que pasar de  crear una macro a crear código (script) es pasar de utilizar una funcionalidad avanzada incorporada al servicio (3) a adentrarse en el mundo de la programación. Para ello, como sabemos, hace falta lógica de programación y conocimiento del lenguaje. A facilitar lo primero dedicamos la sección [Programación] de este blog (también ésta en la que estamos) y la actual a iniciarnos en el conocimiento del lenguaje OOo Basic. En realidad ambas son complementarias.

Pero volvamos a las macros, porque a pesar de sus limitaciones (4) generan un abanico de posibilidades que posiblemente pasen desapercibidas al principio, cuando sólo somos usuarios de Grabar macro. Estas posibilidades se esconden en el IDE, espacio de trabajo que queda oculto a primera vista, especialmente si la propia funcionalidad Grabar macro permanece también oculta.

Esa posibilidad no es de descartar, ya que no tiene por qué estar activada en la configuración inicial de LibreOffice, así que será mejor que empecemos rasgando estos velos.

Sabemos que para acceder a Grabar macro debemos activar el menú Herramientas | Macros. La primera de sus opciones es precisamente Grabar macro, pero cabe la posibilidad de que no aparezca (5). En ese caso, lo primero que tenemos que hacer es hacerla visible. Para ello:
  • Activamos la opción Herramientas | Opciones.
  • Dentro de las que se nos ofrecen activamos LibreOffice | Avanzado
  • Y en Opciones Java (a la derecha del menú anterior) encontramos Funcionalidades opcionales.
  • La funcionalidad Activar grabación de macros (limitada) se encontrará no seleccionada. 
  • La seleccionaremos (clic en el check list correspondiente) y haremos clic en Aplicar y en Aceptar para cerrar la ventana del menú.
Ahora Grabar macro estará disponible y se visualizará como primera opción de Macros, lo que nos permite activar la llamada grabadora de macros, que consiste en una pequeña ventanita emergente...


... en cuyo botón Finalizar grabación deberemos hacer clic cuando hayamos finalizado la secuencia de acciones que queremos automatizar. Lo que obtenemos como resultado es algo que resulta ciertamente confuso al no iniciado: visualizamos sin saberlo un acceso temporal al IDE, pero si no sabemos nada de su existencia es fácil que nuestra macro termine perdida sin que sepamos cómo acceder a ella cuando la necesitamos. Es necesario, por tanto, comprender el proceso a seguir.

Para ello vamos a simular que creamos una macro desde un nuevo documento. Por defecto, este documento no dispone aun de espacio propio para archivar la macro que creemos, algo que resulta imprescindible si deseamos que las macros queden vinculadas al propio documento (6).

Si creamos una macro activando Grabar macro y finalizamos el proceso tal y como expliqué antes, emerge automáticamente una ventana (una de las visualización del IDE, en realidad) que, por defecto, posicionará nuestra macro no en el documento desde el que la estamos creando, sino en Mis macros. Podemos guardarla ahí, pero es posible que después no sepamos cómo recuperarla, así que, al menos para empezar, es preferible guardarla en el propio documento.

Para ello, antes de finalizar el proceso, nos posicionaremos en el icono que representa nuestro documento (se sitúa al final del listado de componentes) y hacemos clic en Módulo Nuevo, aunque es suficiente con hacer clic en Guardar, ya que al no existir ningún módulo (ni carpeta o directorio), LibreOffice lo crea por defecto (Module1), después de crear el directorio Standard.

Ahora nuestro archivo consta (en el IDE) de una carpeta Standard y un módulo Module1 donde está guardada nuestra primera macro. Las siguientes que grabemos lo será en esta ubicación, pero deberemos tener cuidado de darles un nombre propio, ya que de no hacerlo asume Main (principal) como nombre por defecto para esta nuestra segunda macro (7)

Hasta aquí ya sabemos crear macros, pero hace falta usarlas, cosa que requiere un nuevo ajuste en el funcionamiento que por defecto tiene LibreOffice. Me refiero al nivel de seguridad con el que está inicialmente configurado, que impide la activación de macros (8). Como seguramente este será nuestro caso (en estos momentos), deberemos modificar esa configuración inicial. Para ello:
  • Volvemos al menú Herramientas | Opciones
  • Seleccionamos ahora Seguridad y (a la derecha) hacemos clic en Seguridad de macros.
  • Se activa una ventana emergente que nos da cuatro opciones.
  • Personalmente opto por Medio, por el control que me da sobre la activación o no de las macros. No recomiendo la opción Bajo por los riesgos que comporta ni Alto por lo que complica el uso de macros personales, que es nuestro objetivo.
  • Sólo nos resta hacer clic en Aceptar para finalizar este proceso.
A partir de este momento, cuando carguemos en memoria un documento que contenga macros, antes de darnos acceso a él, LibreOffice nos informará que el documento contiene macros y nos dará la doble opción de activarlas no inhibirlas. Dado que pretendemos trabajar con nuestro código o con código de confianza (y sólo en esos dos casos) lo lógico es que permitamos la activación de macros, pero siempre será nuestra decisión y responsabilidad.

Toca ahora acceder a las macros que acabamos de crear para probar su funcionamiento. Para ello seguimos trabajando meramente con las funcionalidades de LibreOffice, ajenos aun a la creación de código y al código que, sin saberlo, hemos creado. Para ello:
  • Seleccionamos la opción Herramientas | Macros | Ejecutar macro
  • En la ventana emergente Selector de macros nos posicionamos en el icono que representa nuestro documento y hacemos clic en la crucecita que precede al icono.
  • Se despliega su estructura de carpetas (biblioteca o librería Standard, es como se denomina a lo que aparece a continuación) y hacemos de nuevo clic en la crucecita que precede a Standard (9).
  • Se muestra el contenido de Standard, en estos momentos únicamente Module1.
  • Haciendo clic en Module1 se muestra en Nombre de macro (ventana a la derecha de Biblioteca) el listado de las macros que hayamos creado.
  • Haciendo clic en una de las macros esta se activará y ejecutará en el documento la secuencia de acciones que hayamos grabado.
Estaremos un rato entretenidos grabando y activando macros; es necesario para familiarizarse con esta funcionalidad y con las posibilidades que tiene generar nuestras propias macros, pero aunque resulte entretenido y útil para determinadas necesidades, no tardaremos en descubrir también sus limitaciones (10). Por suerte OOo Basic no sólo nos permite superar esas limitaciones; también nos va a permitir integrar las macros como parte de nuestro propio código, con lo que lo hecho hasta ahora no es sólo un inocente divertimento (los hay mucho mejores, claro está) ni tiempo perdido.

Hasta aquí hemos aprendido a crear macros mediante la funcionalidad Grabar macro de LibreOffice, demostrando saber usar funcionalidades complejas de la suite; hemos activado esa opción (si no se encuentra disponible); sabemos guardar nuestras macros en el documento desde el que las creamos; sabemos también regular el nivel de seguridad con el que queremos trabajar en LibreOffice y, finalmente, somos capaces de activar nuestras macros para que trabajen por nosotros. 

No son pocas las habilidades que hemos desarrollado en tan poco tiempo, pero lo verdaderamente interesante y útil está aun por llegar. De momento, podemos dar un formato complejo a un texto, crear tablas, listados y contenido, pero también hemos podido comprobar que si queremos dirigir un documento a una persona concreta, citar por su nombre a un niño o a un profesor, informar de una hora y un lugar concretos o comentar los resultados del alumno en un área del currículo nos vemos obligados bien a crear una macro específica para cada caso, situación o contenido concreto... o a modificar el texto que crea la macro sustituyendo unos datos por otros. En estas circunstancias, Grabar macro es de relativa ayuda... o de ninguna. 

Como ya dije, OOo Basic nos permite superar esas limitaciones. Por eso es importante que aprendamos ahora los elementos básicos de este lenguaje. Una vez que los hayamos aprendido, podremos volver sobre nuestras macros (11) para aprovechar mucho y bien lo que nos aportan. Pero, de momento, deberemos hacer un alto en este camino y recorrer otro más largo, pero necesario y sumamente interesante. No se trata precisamente de la travesía de ningún desierto, aunque se requiere paciencia, estudio, práctica y esfuerzo. Merece la pena.

NOTAS

(1) También, y primeramente, OpenOffice. 

(2) Para los amigos: secuencia Herramientas | Macros | Grabar macro.

(3) Crear macro no es la única ni quizá la más útil de esa categoría de funcionalidades. Desde la perspectiva del usuario, particularmente interesante me parece Combinar correspondencia o el uso de formularios, ya que permiten dotar a los documentos de recursos muy interesantes de cara al trabajo de los profesionales de los SEO. No obstante, Grabar macro es la puerta lógica de acceso a la programación mediante OOo Basic, y eso nos permite ir mucho más allá en la creación de recursos ajustados a nuestras necesidades de lo que podemos avanzar con aquellas.

(4) De por sí, una macro no aporta gran cosa de utilidad, salvo quizá en procesos complejos de formato y la automatización de la escritura de contenido invariable. Es necesario recurrir al uso de variables para personalizar el contenido textual, algo que requiere conocimiento del lenguaje de programación. 

(5) En ese caso, la primera opción visible será Ejecutar macro, pero el usuario no iniciado en el uso de macros no obtendrá ninguna utilidad de ella, ya que no se pueden ejecutar macros que no se han creado. 

(6) Tendremos ocasión de comprobar que ésta no es la única opción, pero por el momento eso no nos interesa ni nos resuelve nuestro problema actual; al contrario, puede resultar engañoso.

(7) La primera es posible que haya sido guardada por defecto como Macro1. Si no queremos sustituirla por la segunda macro no la seleccionaremos. Hay que observar que en Nombre de macro consta aquella en que se ubica la funcionalidad Grabar macro, pero podemos cambiar ese nombre por cualquier otro (sin espacios en blanco), de modo que no sustituyamos una macro ya creada por la nueva.

(8) Esto es debido al riesgo que comporta el uso de código no seguro, categoría en la que se considera están las macros, dado que potencialmente pueden haber sido pensadas como software malicioso. Dado que somos nosotros quienes creamos macros en nuestro beneficio, este no es el caso, pero LibreOffice no lo sabe y cautelosamente no lo presupone.

(9) Como dije antes (7), y ahora concreto más, al crear nuestro Module1 se crea automáticamente este directorio que, por su naturaleza de contender de código, se denomina Biblioteca en español, pero que se conoce más como Librería por esa fea costumbre que tenemos los hispanos de traducir literalmente los términos ingleses (Library).

(10) En cuanto a utilidad estoy pensando en el formateo de documentos o en su estructuración, por ejemplo. Las limitaciones son evidentes, pero Grabar macro no deja de ser una buena solución definitiva en ciertos casos, provisional en otros y complementaria en tercer lugar.

(11) En ese momento, no muy lejano, sobre su código, que por ahora nos es completamente desconocido.

miércoles, 24 de abril de 2024

OOo Basic

Características del lenguaje OOo Basic

Aunque todos los lenguajes de programación tienen, en lo básico, mucho en común (y oportunidades tendremos de comprobarlo en las entradas de esta sección), OOo Basic (y también VBA) tiene características específicas que interesa conocer desde el inicio de su aprendizaje.



Este lenguaje procede del desarrollado para OpenOffice y se define como lenguaje de macros. Es fundamental entender lo que implica esta categorización, ya que, aunque la considero poco precisa y hasta cierto punto confusa, resumen lo que OOo Basic tiene de específico (insisto: también VBA): es un lenguaje para trabajar desde dentro de las suites OpenOffice y LibreOffice, desde cada uno de sus servicios (Writer, Calc...), como recurso para automatizar procedimientos.

Dentro de eso que se ha venido en llamar competencia digital docente, más específicamente en lo que se refiere a la lógica de programación competencia (un tanto olvidado, como ya tuve ocasión de [comentar]) y más en concreto aun en lo referido a la competencia ofimática ([ver al respecto]), el conocimiento orientado a la práctica de un lenguaje como OOo Basic nos permite hacer un uso mucho más potente y eficiente de unos recursos que (para los SEO) son fundamentales.

Fundamentales por la propia naturaleza de nuestras funciones y del trabajo cotidiano. Y fundamentales también por el ahorro de tiempo que supone lo que deriva de ese conocimiento: la posibilidad de automatizar los procedimientos de trabajo y la creación documental que conllevan. Esto viene a ser equivalente a decir incremento de la competencia ofimática.

El lenguaje OOo Basic aporta, por tanto, ciertas ventajas, aunque también presenta limitaciones que no tienen otros lenguajes de propósito general, no "encerrados" en la suite ofimática (1). Pero ahora me interesa destacar algunas de las innegables ventajas que, en mi opinión, hacen que merezca la pena trabajar con él:
  • Usar OOo Basic (2) implica incrementar exponencialmente el aprovechamiento del conocimiento de los servicios de las suites ofimáticas. Dicho de otra forma, no partimos de cero, y estos conocimientos previos suponen tener andado un buen trecho del camino.
  • En relación con lo anterior, los resultados que podemos obtener con OOo Basic son directamente aprovechables desde los propios servicios, con independencia de cuáles sean éstos y de la frecuencia y familiaridad de uso que tengamos de ellos (3)
  • Las habilidades que se adquieren en el uso de funcionalidades de cierta complejidad se ven potenciadas con el conocimiento y uso de OOo Basic. La relación entre ambos (funcionalidades avanzadas y creación de script) es bidireccional: ambas se potencian, aunque puedan considerarse alternativas.
Podemos resumir todo lo anterior diciendo que OOo Basic como parte que es de la suite LibreOffice complementa y potencia sus funcionalidades, transformando lo que son simples documentos en una especie de aplicación o programa que, además de automatizar la generación de contenidos, incorpora procesos de análisis de datos de cierto nivel de complejidad, tanto como necesitemos o seamos capaces de desarrollar.

La ventaja para el profesional son evidentes: es él mismo el que, desde su conocimiento profesional y de sus específicas necesidades, desarrolla un recurso orientado a proporcionarle ayuda. Es por eso que, aunque podemos enmarcar el uso de OOo Basic dentro del desarrollo de la competencia ofimática, en realidad se supera ampliamente esta delimitación, ya que se adentra en el conocimiento y uso funcional de las habilidades de programación.

Cierto es que nada es gratis, y en este caso se requiere conocimiento del lenguaje. A ello está dedicado este apartado.

NOTAS

(1) Me refiero, por ejemplo, a Python. No es éste un tema que me interesa desarrollar ahora, ya que tiempo y espacio habrá para navegar por esos mares.

(2) O VBA para los que opten por MSO, que en esto del lenguaje no hay mucha diferencia de funcionalidad, aunque si de código, como también de servicios. La apuesta de la Administración educativa asturiana por los servicios de Microsoft no es un secreto. Sus razones tendrá, pero ni el precio ni la utilidad, ni siquiera la versatilidad pueden ser argumentos a favor de esta opción.

(3) Constato reiteradamente que la frecuencia de uso, por si misma, no permite incrementar el nivel de conocimiento que se tiene de ellos. Y lo que es igualmente limitante: los servicios realmente utilizados se limitan al procesador de texto y, muy en segundo lugar, de los servicios de creación de presentaciones. Las hojas de cálculo y no digamos las bases de datos son, en la práctica, auténticos desconocidos. Considero que esto evidencia la insuficiencia de considerar que el uso genera por si mismo un incremento conocimiento de las funcionalidades de las herramientas y consecuentemente un mayor aprovechamiento. Siendo esto así (y lo es), se hace aun más necesaria una formación específica sobre duchas funcionalidades, incluyendo la propia y específica sobre los mal llamados "lenguajes de macros". 

Usos. Textos

Posicionamiento en el texto mediante marcadores


Cuando hablamos de posicionar el cursor en el documento, comentamos que mediante macros y/o script nos podemos posicionar sin dificultad tanto al inicio como al final de documento, siendo suficiente (en el caso de script) con indicarlo en la instrucción. Pero cuando trabajamos con textos pre-escritos (esos en los que hay que completar huecos con palabras o dotar de contenido por secciones), esas opciones no aportan soluciones satisfactorias.



Son muchas las situaciones con las que es suficiente con posicionarse al inicio o al final del texto escrito, especialmente cuando ese texto se "escribe" partiendo de un documento en blanco. Es suficiente con una instrucción como la siguiente...

oText.insertString(oText.getStart(),sTexto & Chr(13), False)

... para escribir al inicio del documento, o como esta otra para hacerlo al final...

oText.insertString(oText.getEnd(),sTexto & Chr(13), False)

... como hemos tenido ocasión de explicar en [esta entrada]. Pero la cosa se complica cuando, en vez de partir de un documento en blanco, tenemos que automatizar la composición de uno que ya nos viene dado como modelo, sea éste un documento con huecos (por decirlo de alguna manera)...


... o de documento complejo, establecido como de uso obligado y diferenciado en apartados. El modelo de Informe es un ejemplo claro.

En estos casos necesitamos recurrir a otra estrategia. Contamos con varias alternativas, pero después de probarlas (1), y aunque no sea una solución carente de ciertas dificultades y limitaciones, personalmente considero que el uso de marcadores es opción más flexible, simple y funcional. A ello ayuda la sencillez del código básico de acceso a un marcador (2)

oMarca1 = ThisComponent.getBookmarks().getByName("Marcador1")
oMarca1.getAnchor.setString("Inserto texto")

El uso primario de los marcadores es facilitar el acceso directo a determinadas posiciones del documento para insertar el contenido que corresponda. Para ello hay que pulsar F5 (3) para acceder al Navegador del documento. En él encontraremos un listado con todos los contenidos reales y posibles del documento. Deberemos buscar Marcadores y desplegar su listado. Después seleccionamos el deseado y hacemos doble clic (izquierdo) para que el cursor se posicione en el lugar que ocupa el marcador (4).

Este procedimiento ayuda a trabajar con documentos en los que, bien a modo de texto mutilado, bien por el empleo de tablas, necesitemos agilizar el recorrido por el documento sin necesidad de utilizar el tabulador (para el desplazamiento por las celdas de la tabla) o (y principalmente) el ratón. A ello ayuda que el Navegador permanece disponible y es suficiente con hacer doble clic en cada uno de los marcadores para realizar el posicionamiento. No obstante, mediante código (script OOo Basic) podemos sacar mucho más provecho a este recurso, automatizando la composición de texto basados en documentos-modelo.

Para ello, lo primero que tenemos que hacer es crear los marcadores. Esta tarea lleva su tiempo si el documento es extenso y/o complejo, pero merece la pena. 

Para crear un marcador deberemos:

  • Posicionarnos en el lugar del texto en que deseemos crear el marcador
  • Activar el menú Insertar y seleccionar la opción Marcador (Insertar|Marcador)
  • Escribir el nombre con el que queremos identificar al marcador en la ventana emergente que resulta de proceso anterior...
  • ... Y hacer clic en el botón Insertar de esa misma ventana.

Dado que estamos trabajando con un menú emergente (posiblemente un cuadro de diálogo o interface equivalente), no nos permite acceder al documento y cada vez que hacemos clic se cierra. Esto obliga a que tengamos repetir el proceso, y en el mismo orden, tantas veces como marcadores deseemos incluir (5).

Dentro de esta fase del procedimiento, un tema a plantear, que no carece de importancia, es qué nombre a dar a los marcadores. La respuesta (opino) depende del modo en que pensamos utilizarlos. En todo caso, hay dos opciones básicas:

  • Crear nombres descriptivos (no importa que sean de cierta longitud) si vamos a usar los marcadores directamente desde el documento (esto es, sin usar script) o si el acceso mediante código no implica ni requiere un proceso secuencial repetitivo: los nombres descriptivos tienen la ventaja de ser inteligibles al usuario.
  • Crear identificadores (nombres) breves con un índice numérico consecutivo e incremental (v.g. marca1). Esta es una buena solución cuando vamos a trabajar con script y pensamos usar bucles para automatizar la escritura del contenido recorriendo los marcadores: de este modo es el script será mucho más sencillo y eficiente. 
  • Evidentemente podemos combinar ambas opciones (6).
Finalizaré explicando el modo de usar un bucle For...Next para escribir un texto. No es el único uso de los marcadores, pero sí posiblemente el más eficiente y tiene interés entender cómo hacerlo (7).
  • Primero. Creo los marcadores (p.e. 5 marcadores) en el texto según lo ya visto, nombrándolos del modo ya indicado (p.e. mrc0 a mrc4).
  • Creo variables y matrices: 
    1. variable tipo objeto para acceder al marcador (Dim oMarca As Object) y variable integer como contador para el bucle (Dim i As Integer).
    2. Matriz para los bloques de texto (párrafos) que vamos a escribir en el documento (Dim mTextos(4) As String) (8)
  • Tercero. Doy contenido textual a los elementos de la matriz (p.e. mTexto(0) = "Texto posicionado en el marcador mcr0")
  • Cuarto. Creo el bucle For: For i = LBound(mTextos()) To Ubound(mTextos()) (9)
  • Quinto. Utilio el valor secuencial e incremental del contador (i) para ir escribiendo (secuencialmente) el contenido de la matriz en las posiciones de los marcadores:
oMarca = ThisComponent.getBookmarks().getByName("mcr" & i)
oMarca.getAnchor.setString(mTexto(i))

  •  Cierro el bucle For con la instrucción Next
Este será el código completo:

Dim oMarca As Object
Dim i As Interger
Dim mTextos(4) As String

mTextos(0) =  "Texto posicionado en el marcador mcr0"
mTextos(1) =  "Texto posicionado en el marcador mcr1"
mTextos(2) =  "Texto posicionado en el marcador mcr2"
mTextos(3) =  "Texto posicionado en el marcador mcr3"
mTextos(4) =  "Texto posicionado en el marcador mcr4" 

 For i = LBound(mTextos()) To Ubound(mTextos()) 

oMarca = ThisComponent.getBookmarks().getByName("mcr" & i) (10)
oMarca.getAnchor.setString(mTexto(i))
Next 

Cada vez que el bucle hace un recorrido, el valor de i se incrementa (por defecto) en +1.

Uso una única variable objeto para asignar a su espacio de memoria cada uno de los objetos marcador. Esto simplifica el procedimiento y ahorra memoria, ya que en cada ciclo oMarca contendrá un objeto marcador diferente. (11

El uso del contador i como parte del nombre del marcador ("mcr" & i)  y como índice del elemento de la matriz (mTexto(i)) permite emparejar marcador con contenido textual sin que sea necesario especificarlo expresamente.

Aunque los procedimientos de trabajo pueden ser mucho más complicados, en lo básico éste es el modo de trabajar con marcadores y bucles para automatizar la escritura de texto. Es suficientemente sencillo para que te animes a utilizarlo siempre que la lógica del algoritmo lo permita. Ganarás en tiempo y en eficiencia.

NOTAS

(1) Combinar correspondencia, vincular campos de bases de datos, desplazarse por el documento mediante código, transformar el documento en un conjunto de tablas y desplazarse de celda en celda, son algunas de ellas. Algunas son sencillas en cuanto a generar el desplazamiento, pero complejas de transformar el documento-base al formato requerido (como el uso de tablas), otras son aparentemente sencillas, ya que están integradas como funcionalidades del servicio (Writer), como combinar correspondencia o vincular datos, pero resultan poco funcionales como solución para textos complejos y exigen un buen trabajo previo con la base de datos (que puede ser una hoja Calc, no necesariamente un base de datos en sentido estricto. En la práctica he utilizado las diferentes opciones y no considero que sean plenamente satisfactorias, aunque para textos sencillos pueden servir perfectamente.

(2) De esta opción ya hablamos en una [entrada anterior] pero considero conveniente tratarla de nuevo y de forma más detallada em una entra  específica para comentar el conjunto de procedimientos que implica, su secuencia de desarrollo y la diversidad de situaciones en las que podemos utilizarla.

(3) Según la configuración del teclado es posible que sea necesario pulsar simultáneamente F5 + otra tecla. En mi caso (Surface) necesito pulsar Fn+F5

(4) Los pueden ser visibles o estar ocultos. Podemos alternar entre las dos opciones activando o desactivando la opción Marcar campos (Ver|Marcar campos)

(5) Especialmente cuando el número de marcadores a crear es elevado, este procedimiento resulta tedioso y, hasta donde yo sé, no es posible automatizarlo. Agradecería información al respecto.

(6) Esta tercera solución es perfectamente válida y ocasionalmente la más útil, pero (en mi opinión) siempre que podamos resolver el algoritmo utilizando un bucle (con lo que este implica en cuanto a denominación), es mejor opción que crear accesos puntuales a marcadores determinados.

(7) Por economía ahora me salto, por sabido el procedimiento, de acceso al documento y me centro en el específico de trabajo con los marcadores. Otros usos posibles y frecuentes de marcadores son el posicionamiento en tablas (y su recorrido) o el completar textos mutilados. No obstante, en cuanto a procedimiento no existe diferencia con el que aquí se explica. Cierto que podemos optar con el primer procedimiento (individualizar el posicionamiento en lugar de usar un bucle), pero esta forma de trabajar queda explicada en la presentación del uso de marcadores como recurso de posicionamiento.

(8) Obsérvese que en este caso hemos considerado que la matriz tiene 5 elementos (0-1-2-3-4) y que es de tipo string. El número de elementos tiene que coincidir con el de marcadores, como es el caso en nuestro ejemplo.

(9) También podemos usar la expresión For i = 0 To 4, ya que conocemos el inicio y el fin de la matriz, pero la fórmula elegida nos permite trabajar con cualquier número de elementos de la matriz, así que si añadimos o eliminamos elementos no es necesario modificar la sintaxis del bucle. No nos debemos olvidar de la necesaria igualdad entre los elementos de la matriz y el número de marcadores si el objetivo es el que se enuncia al principio del ejemplo. En caso contrario (nada excepcional, por otra parte), sólo se escribirán textos en los marcadores que equivalgan al número de elementos de la matriz.

(10) Podemos emplear otras fórmulas ("mcr" + i, o incluso "mcr" & CStr(i), que sería la forma más correcta), pero el efecto práctico será el mismo. En caso de duda o error, podemos probar las diferentes opciones y quedarnos con la que nos satisfaga. El error puede venir dado por el uso de Option explicit que nos obliga a ser estrictos con la declaración de las variables y sus tipos.  

(11) La alternativa pasa por trabajar con una matriz de elementos objeto (Dim oMarca(4) As Objet), lo que nos asegura que cada espacio de memoria contiene sin pérdida de contenido un objeto marcador específico. En consecuencia modificaremos la sintaxis de la primera línea del contenido del bucle como sigue: oMarca(i) = ThisComponent.getBookmarks().getByName("mcr" & i). Obsérvese que también usamos i como referencia de índice (elemento) de la matriz oMarca(). Aunque no es relevante en este caso, esta forma de proceder implica un incremento del gasto memoria RAM del sistema, ya que empleamos 5 espacios de memoria en lugar de uno.