miércoles, 24 de abril de 2024

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. 

No hay comentarios:

Publicar un comentario

Comenta esta entrada

Nota: solo los miembros de este blog pueden publicar comentarios.