domingo, 31 de marzo de 2024

Usos. Textos.

Enumeración

Inicio con esta entrada una nueva sección dentro del apartado o capítulo que he denominado Usos y que tiene que ver con la escritura de unos textos que requieren un tratamiento especial: me refiero a las enumeraciones y los listados. Por simplificar la estructura de contenidos de Usos he considerado conveniente incluir en esta sección también el trabajo con tablas, ya que uno de los usos de las tablas (aunque más orientado a la presentación y estructuración de los contenidos en el texto), también es una de las formas en las que podemos escribir listados.


En el proceso de escritura de textos nos encontramos, con cierta frecuencia, con enumeraciones y listados. Aunque en la escritura manual ambos no presentan mayor complicación (1),  es en la automatización de la composición del texto cuando ambas presentan especificidades, no siendo suficiente con los recursos de escritura que ya vimos anteriormente en este mismo apartado (Usos). En esta entrada trataré sobre la composición de enumeraciones y en siguientes sobre listas y tablas.

La escritura manual de una enumeración (lunes, martes, miércoles y jueveses muy simple: escribimos cada uno de los elementos que la componen, separándolos por comas y usando bien la conjunción, bien la disyunción entre el penúltimo y el último elemento de la enumeración. ¿Pero cómo reproducir este proceso en la automatización del texto?.

El problema de la enumeración (aunque podemos considerarlo meramente de corrección de estilo y gramatical) está en el tratamiento de los conectores (coma y/o disyunción vs. conjunción). La causa de las "dificultades" está en el conocimiento vs. desconocimiento previo del número de elementos que componen la enumeración. Otras cuestiones a considerar en la creación del código son si la entrada de datos queda a disposición del usuario o se dan por supuestas y si nos vamos a basar en la concatenación de contenidos asociados a una (o varias) variable(s) o en el uso de matrices... o en la combinación de ambas soluciones.

El "caso" más simple es cuando los elementos vienen dados en el código y, además, conocemos de antemano tanto el número de elementos como su contenido concreto; en este caso tenemos información cierta de los contenidos (y no necesitamos solicitarlos al usuario) y sabemos qué conector utilizar en cada momento. Esta situación (2) podemos tratarla tanto mediante variable(s) concatenadas incrementales, como mediante el listado de los elementos de la matriz.

Supongamos que se trata de enumerar, por ejemplo, los días de la semana (3), datos conocidos de antemano y perfectamente tratables como variables o como elementos de una matriz, como parte de un texto que, por simplicidad, vamos a obviar.

Esta enumeración podemos abordarla, como dije, mediante mediante variables (a las que asignar los nombres de los días, o mediante una matriz. Dado que el primer sistema hace que el código sea más simple pero también más costoso de escribir, opto por el uso de una matriz. Además, en este caso, lo importante no es tanto el soporte de los datos (variables vs. matriz) como el sistema de  concatenación, que es lo que me interesa explicar en primer lugar. Veamos este  script básico:

Sub Main1

VarSis

Dim mDiasSem(6) As String
Dim i As Integer

 

mDiasSem(0) = "lunes"
mDiasSem(1) = "martes"
mDiasSem(2) = "miércoles"
mDiasSem(3) = "jueves"
mDiasSem(4) = "viernes"
mDiasSem(5) = "sábado"
mDiasSem(6) = "domingo"


For i = LBound(mDiasSem()) To UBound(mDiasSem()):
Escribir(mDiasSem(i))
If i < UBound(mDiasSem()) - 1 Then
Escribir(", ")
ElseIf i = UBound(mDiasSem()) - 1 Then
Escribir(" y ")
End If
Next

End Sub

Se pueden identificar tres parte en el script (4): en la primera se declara la matriz mDiasSem() y una variable contador (i); en la segunda se dota de contenido a la matriz y en la tercera se desarrolla el procedimiento de escritura de la enumeración. Estés última la que nos interesa ahora.

Consta ésta de un ciclo For articulado en torno a la identificación de las posición o índices inicial (función LBound()) y final (función UBound()) de la matriz, que se asocian al contador i. El uso de estas funciones en lugar de los valores directos (0 y 6 respectivamente) facilita que esta línea de código sea válida para cualquier matriz con independencia del número de elementos que tenga.

Dentro del bucle incluimos la instrucción de escritura Escribir(mDiasSem(i)) y un condicional: la primera escribe en el documentos los contenidos de la matriz y la segunda (el condicional if), genera la concatenación y establece la forma en que se concreta gramaticalmente: la coma (,) hasta que el penúltimo elemento... 

If i < UBound(mDiasSem()) - 1 Then

... y la conjunción entre éste y el último

ElseIf i = UBound(mDiasSem()) - 1 Then

La concatenación resultante lo es por la acción sucesiva (cíclica) de la llamada a la subrutina de escritura, la cual podemos simular ahora  como sigue, entendiendo que cada elemento va precedido de la llamada a la subrutina Escribir() (5)...

 mDiasSem(i) + ", ")+ mDiasSem(i) +.... + " y " + mDiasSem(i)

... siendo éste el resultado que obtendremos:

 lunes, martes, miércoles, jueves, viernes, sábado y domingo

La segunda situación se presenta cuando desconocemos a priori el número de elementos que contiene la enumeración ni su contenido concreto y hacemos la enumeración usando variables (6). En este caso el script (uno de los posibles) sería el siguiente:

Sub Main2

VarSis

Dim DiasSem As String, Conector As String, Dias As String
Dim i As Integer, a As Integer

a = CInt(InputBox("Número de elementos de la lista"))
a = a - 1

For i = 0  To a:
DiasSem =InputBox("Día de la semana")
If i < 1 Then
Dias = DiasSem
ElseIf i = a Then
Conector = " y "
Dias = Dias & Conector & DiasSem
Else
Dias = Dias & ", " & DiasSem
End If
Next

Escribir(Dias)

End Sub

En este caso distinguimos cuatro partes dentro del script:

  • En la primera establecemos las variables: tres string y dos integer. Las segundas son contadores y dentro de las primeras, dos de ellas (DiasSem y Dias) sirven para concretar el contenido de la enumeración y la tercera (Conector) sirve para especificar los conectores a emplear.
  • En la segunda parte establecemos el número de elementos que tendrá la enumeración. En este caso lo hemos hecho mediante un recurso elemental de interface (InputBox())para que esté en función de la elección del usuario (7). Debido a esto, para evitar la confusión que podría darse entre número de elementos de la enumeración y el elemento último del ciclo (ya que el primer valor del contador suele ser por sintaxis 0 y no 1), he realizado una reasignación del contenido de contador secundario (a = a-1).
  • La tercera parte es similar en cuanto a estructuras a la de Main1, pero muy diferente en cuanto a las instrucciones que contiene. La explicaré en detalle al final de estos epígrafes.
  • Y la última y final es la de escritura de la enumeración en el documento, haciendo uso de la subrutina Escribir(Dias). Nótese que, en este caso, la instrucción de escritura no es cíclica (no está dentro de For) ya que la concatenación, que sí se desarrolla dentro del bucle, da como resultado una variable generada mediante un proceso de asignación de contenido que incluye el contenido previo de esa misma variable. Explico todo esto a continuación.
El ciclo For tiene como límite el que defina el usuario en a (2º parte), o que equivale a decir el número de días que va a seleccionar, no cuáles. Para esto, también mediante InputBox(), la instrucción (DiasSem =InputBox("Día de la semana")) le permite introducir los valores que desee hasta alcanzar su total a. En DiasSem, por tanto, se almacenan los valores individuales.

A continuación, mediante la estructura condicional If-ElseIf-Else creamos el contenido que resultará en concatenación sobre la variable Dias, que es la que se emplea como argumento para la llamada a la subrutina Escribir (parte 4ª). La variable Dias es, pues, el soporte en el que realizamos el proceso de concatenación de la secuencia, y sobre la cual debemos articular el ajuste del contenido de la variable Conector. Esta es la razón de la estructura condicional: inicialmente (para i = 0, o lo que es lo mismo, para i<1) Dias contiene el valor de DiasSem, pero en los pasos siguientes del ciclo, entre en funcionamiento la concatenación que incluye la variable Concatenar (8). Si llegamos al final de la enumeración el conector será "y", pero en otro caso empleamos como conector la coma (,).

Gracias a las posibilidades de interacción del código con el usuario, mediante este script podremos incluir en la enumeración tanto elementos como deseemos, además de los elementos que deseemos. No estamos limitados a una lista previa (a un marco de referencia, en realidad), como tampoco a un número prefijado de componentes, como sí sucedía en el primer script.

Veamos, por último, un tercer procedimiento que corresponde también con una tercera situación, menos restrictiva que la primera, pero más que la segunda: disponemos de todos los datos posibles (universo) para la enumeración y seleccionamos de entre ellos los que nos resultan útiles (conjunto). Se trata de una situación que quizá se da con más frecuente en la elaboración de listados que en enumeraciones (donde puede ser más frecuente el modelo anterior), pero también sirve, muy especialmente, cuando nos interesa y conviene controlar el contenido que tendrá como referencia (universo) la enumeración o el listado. Especialmente si ese universo del que extraer el conjunto es extenso y/o difícil de recordar de memoria (para el usuario).

Sub Main3

VarSis

Dim mDiasSem(6) As String, mMisDias()As String
Dim Dia As Integer
Dim i As Integer, a As Integer

mDiasSem(0) = "lunes"
mDiasSem(1) = "martes"
mDiasSem(2) = "miércoles"
mDiasSem(3) = "jueves"
mDiasSem(4) = "viernes"
mDiasSem(5) = "sábado"
mDiasSem(6) = "domingo"

a = 0

For i = LBound(mDiasSem()) To UBound(mDiasSem())
Dia = MsgBox (mDiasSem(i),4,"MIS DIAS")
If Dia = 6 Then
ReDim Preserve mMisDias(a)
mMisDias(a) = mDiasSem(i)
a=a+1
End If
Next

For i = LBound(mMisDias()) To UBound(mMisDias()):
If i < UBound(mMisDias()) - 1 Then
Escribir(", ")
ElseIf i = UBound(mMisDias()) - 1 Then
Escribir(" y ")
End If
Next

Escribir(mMisDias(i))

End Sub

Este script consta también de cuatro partes: la declaración de variables y matrices, la asignación de contenido a la matriz universo, un bucle para construir la matriz conjunto y un segundo bucle para escribir el contenido de ese conjunto en el documento (esto es: para crear la enumeración, o el listado en su caso). Veamos con más detalle cada una de estas partes:

  • En la primera parte se declaran las matrices y variables. Las dos matrices cumplen funciones de universo (mDiasSem(6)) y conjunto (mMisDias()): en la primera se concreta el tamaño ya que es conocido, pero no en la segunda por no serlo. Dentro de las variables se distinguen dos grupos: Dia, que servirá para contener el valor numérico de la respuesta de elección del usuario y dos variables contador (i y a) para el funcionamiento de los bucles.
  • En la segunda parte se asigna contenido a la matriz universo (mDiasSem()) para que esté disponible para el proceso de selección de contenidos que pasarán a la matriz conjunto (mMisDias())
  • La tercera parte se inicia col la asignación de valor inicial al contador a (a=0), aunque lo fundamental en ella es el bucle For cuya estructura explicaré al final de esta descripción. Este primer bucle tiene por misión facilitar la elección de los contenidos que conformarán la matriz conjunto (mMisDias())
  • Finaliza el script (cuarta parte) con un segundo bucle For, cuya función es facilitar la escritura del contenido seleccionado (matriz mMisDias()) en el documento, por lo que en él se hace uso de la subrutina de escritura (Escribir). También explicaré más detalladamente el funcionamiento de este bucle.
Paso a detallar cómo funciona el bucle de la parte tercera:
  • Utilizo las funciones LBound() y UBound() sobre la matriz mDiasSem() (conjunto) asociadas al contador i a fin de facilitar la generalización del funcionamiento del bucle. Dado que las dimensiones de la matriz conjunto son conocidas, podría sustituir esas funciones por los valores directos (0 - 6), pero es más funcional utilizar los valores resultantes de esas funciones, ya que así se ajusta el bucle a las dimensiones de cualquier matriz.
  • La instrucción que sigue (Dia = MsgBox (mDiasSem(i),4,"MIS DIAS")) permite que el usuario selecciones los valores de la matriz conjunto al incluirla como primer parámetro de la función MsgBox(), la cual se utiliza aquí como función (y no como sistema de información al usuario), ya que lo que importa es el valor (6 vs. 7) que resulta de la pulsación de los botones (-No) que contiene dicha función como segundo parámetro (4) (9)
  • En función de la elección (vs. No) se obtiene un valor (6 - 7) que sirve como argumento para que se cumpla o no la condición que se establece en el condicional If que sigue tras la elección (If Dia = 6 Then). El valor de referencia (6 <- ), que indica que se cumple la condición exigida (supone que se ha seleccionado el elemento de la matriz conjunto) permite que se desarrolle el proceso subsiguiente.
  • Este proceso implica tres pasos:
    • Redimensionar la matriz conjunto manteniendo su contenido previo (ReDim Preserve mMisDias(a)) en  función al valor del contador a en ese momento del ciclo.
    • Pasar el valor seleccionado (mDiasSem(i)) como elemento de la matriz conjunto (mMisDias(a) = mDiasSem(i))
    • Asignar un nuevo valor a a (a=a+1) para incrementar en el siguiente ciclo la dimensión de mMisDias(a).
De este modo es el usuario el que selecciona los valores que necesita y la matriz conjunto resultante de estas elecciones queda dimensionada al número de elecciones positivas del usuario, esto es: a su contenido real.

El segundo bucle For (parte cuarta) tiene como objetivo la correcta escritura de la enumeración, siendo ésta concatenación de elementos resultante del propio funcionamiento del bucle. De que la gramática sea correcta (10) se encarga el condicional anidado en el bucle: 
  • Si el valor del contador i en ese momento es inferior al límite superior de la matriz (If i < UBound(mMisDias()) - 1), entonces se pasa como parámetro la coma (",") en la llamada a la subrutina de escritura (Escribir(", "))
  • Pero si se alcanza la posición inmediatamente anterior al límite superior de la matriz (ElseIf i = UBound(mMisDias()) - 1), entonces se pasa como parámetro la conjunción ("y") (Escribir(" y "))
En esta entrada hemos visto cómo condicionar un contenido concreto (los conectores gramaticales de una enumeración) a una determinada posición en la secuencia de componentes de una matriz o de la variable resultante de la concatenación de string mediante el uso de estructuras condicionales. También hemos utilizado bucles como herramienta de selección de contenidos y de escritura secuencial de los mismos y hemos trabajado con matrices como origen (universo) y destino (conjunto) de datos. Mediante estos procedimientos hemos construido enumeraciones que se ajustan a las demandas del usuario y a la gramática en su escritura como texto.

Este es el documento que contiene los diferentes script principales y auxiliares.

NOTAS

(1) Las enumeraciones forman parte del proceso básico de escritura del texto y para crear listas disponemos de recursos específicos que aporta el servicio (Writer, en nuestro caso).

(2) Se trata de una "situación" que se puede presentar muy raramente, pero que es necesario contemplarla en esta entrada por coherencia en el proceso de aprendizaje.

(3) Por motivos didácticos, mantendré el mismo ejemplo en el resto de los "casos".

(4) Por simplicidad, y por ser muy conocido, no me detendré a explicar la llamada a VarSis ni incluyo tampoco la macro-subrutina de escritura Escribir() necesaria, no obstante, para el funcionamiento de Main1.

(5) Podemos sustituir el concatenador + por & (ambos funcionales) pero prefiero usar + para diferenciar este procedimiento del que resulta de la asignación de una variable a si misma. En eso consiste la segunda forma de concatenar los contenidos.

(6) Tomar como ejemplo los días de la semana resulta un poco forzado en este contexto, ya que sí sabemos de antemano el universo de contenidos de ese conjunto, pero mantenemos esa referencia para facilitar la comprensión del procedimiento y de sus diferencias con el anterior. Al igual que en el anterior omito explicaciones sobre VarSis y la subrutina de escritura, que es la misma.

(7) Podría haber optado por asignarlo directamente, lo cual sería válido a nivel didáctico, pero el script resultante perdería funcionalidad práctica. El inicio de bucle en i=0 lo es por respetar la sintaxis normal de la instrucción For (For i = 0 To a:)

(8) Ahora Dias resulta de añadir a Dias una secuencia formada por el conector + el contenido de la variable DiasSem en cada vuelta del bucle: Dias = Dias & Conector & DiasSem. Obsérvese que ahora usamos el signo &, que es el apropiado a un cadena resultante de concatenar string.

(9) Estos valores (6 para Sí, 7 para No) están predeterminados por la sintaxis de la función MsgBox() según el lenguaje OOo Basic.

(10) Me refiero aquí al uso del los conectores adecuados ( "," vs. "y") según la posición en la enumeración.

viernes, 29 de marzo de 2024

Recursos. Informe

Informe 2024. Carátula.

Trabajamos en una entrada anterior en la [automatización del apartado 5] del informe y he presentado en otra una propuesta de modificación de las tablas del informe para facilitar su [uso directo desde teclado]. Pero también hemos visto que es posible automatizar un [documentos-modelo] con y sin uso de tablas, empleando marcadores. En esta entrada me propongo crear un docap para automatizar la cumplimentación de la carátula del informe partiendo del documento-modelo original. Es un recurso directamente utilizable como herramienta de trabajo, aunque como docap es mejorable, ya que me planteo realizar sólo un docap simple, pero funcional.


Entiendo por carátula el conjunto de tablas con las que se inicia el informe y que se identifican como apartados 1 y 2. Incluyo también la tabla inicial de identificación del documento.

Dado que se trata de un documento-modelo entendido como prescriptivo, y aunque ya vimos que [es mejorable] para uso "manual" unificando tablas, mantendré intacto el documento original incluyendo como único cambio el empleo de marcadores. Esto exige una preparación previa y una previsión de la relación entre los marcadores, su contenido y la matriz en la que éstos se almacenarán en el script.

Algunos de esos datos exigen cierto grado de procesamiento, pero la mayoría son de uso directo, lo que facilita el planteamiento del sistema de interface y la elaboración del algoritmo. 

Respecto a lo primero decir que, por simplicidad y comodidad me limitaré a usar funciones InputBox() y MsgBox(), aunque una formulación más cuidada podría implicar su sustitución por cuadros de diálogo.

Y en lo que se refiere al algoritmo, se trata en realidad de aplicar lo explicado en las entradas en las que se trata el uso de tablas y marcadores como recurso para automatizar la composición de documentos. En este ámbito, este docap puede considerarse una ejemplificación del uso práctico de esos procedimientos.

En consecuencia con lo anterior, para la explicación del funcionamiento de este docap remito a esas aportaciones previas.

En este [enlace] podrás descargar el docap y en [este otro] la versión plantilla. He incluidos datos ficticios para facilitar la comprobación de su funcionamiento. Si deseas utilizarlo como recurso (esa es la idea) puedes modificarlos desde el IDE del documento original. Para el uso práctico te recomiendo usar la plantilla, así estarás a salvo de posibles fallos y podrás recuperar el original.

jueves, 28 de marzo de 2024

Usos. Textos.

Tablas. Escribir contenido (macros).

Vimos en la entrada anterior cómo crear una tabla, pero no cómo escribir contenido en ella. En esta entrada aprenderemos cómo hacerlo, empezando por usar un conjunto de macros, la mayoría ya conocidos.


Cuando trabajamos con un documento en blanco (este es ahora el presupuesto), además de escribir texto, podemos "dibujar" tablas, pero para automatizar la composición del documento, de poco nos sirve si no sabemos cómo incluir contenido en ellas. Para hacerlo usando macros (1) deberemos seguir una serie de pasos en los que utilizaremos macros simples, la mayoría de ellas ya conocidas.

Lo primero que tenemos que saber es dónde está posicionado el puntero de escritura, lo que significa ser consciente de lo que hemos hecho en el momento que precede a la escritura de la tabla.

Aunque las opciones pueden ser varias, la forma más segura es regresar al inicio del documento...

dispatcher.executeDispatch(document, ".uno:GoToStartOfDoc", "", 0, Array()

... y recorrerlo verticalmente mediante bajar línea...

dim args1(1) as new com.sun.star.beans.PropertyValue
args1(0).Name = "Count"
args1(0).Value = iLin
args1(1).Name = "Select"
args1(1).Value = false
dispatcher.executeDispatch(document, ".uno:GoDown", "", 0, args1())

...hasta situarnos en la celda A1 de la tabla. Una vez estemos en esta posición, la orden de escritura es la misma que para escribir texto...

dim args2(0) as new com.sun.star.beans.PropertyValue
args2(0).Name = "Text"
args2(0).Value = sTxt
dispatcher.executeDispatch(document, ".uno:InsertText", "", 0, args2())

... y el desplazamiento por celdas se resuelve mediante la instrucción...

dispatcher.executeDispatch(document, ".uno:JumpToNextCell", "", 0, Array())

El script siguiente es un ejemplo de uso de este procedimiento para crear una ficha sencilla de un alumno (2):

Sub Tabla

VarSis

Dim mDatosTabla(5) As String

Dim i As Integer

mDatosTabla(0) = "Nombre"
mDatosTabla(1) = InputBox("Nombre","Datos personales","Juan")
mDatosTabla(2) = "Apellidos"
mDatosTabla(3) = InputBox("Apellidos","Datos personales","Carrasco Pérez")
mDatosTabla(4) = "Curso y etapa"
mDatosTabla(5) = InputBox("Curso y etapa","Datos Personales","1º de E. Primaria")

InicDoc

Escribir("Ficha de alumno")

SaltoLinea(1)

MacroTabla (2,3)

InicDoc

BajaLinea(2)

For i = LBound(mDatosTabla()) To UBound(mDatosTabla())
Escribir(mDatosTabla(i))
If i < UBound(mDatosTabla()) Then
SaltoCelda
End If
Next

BajaLinea(2)

SaltoLinea(1)

Escribir("Escribir a continuación el contenido pertinente")

End Sub

Y este el resultado que obtendremos.

Pero si la forma anterior es la más segura, su aparente simplicidad se ve comprometida cuando trabajamos con documentos más complejos, especialmente si contienen varias tablas. En este caso, el cálculo de los movimientos necesarios para situarnos correctamente dentro de las tablas puede dar lugar a errores que complican la automatización del documento.

Contamos con un procedimiento más sencillo que supone mantener la secuencia lineal de composición del documento, incluida la cumplimentación de los datos de la(s) tabla(s) y que se basa en el hecho de que al crear una tabla, y hasta que no se recorre ésta hasta su final, el cursor se encuentra situado en la celda inicial (A1) de la tabla creada. Si iniciamos a continuación la escritura del contenido no necesitaremos retrotraernos al inicio del documento (o de la línea) y desplazarnos después al inicio de la tabla, de forma que, siguiendo la secuencia de lo que sería la escritura del documento mediante teclado, iremos cumplimentando el documento en su totalidad, incluyendo el de las tablas que contenga.

Este segundo script (Tabla2) es el que se muestra a continuación (3) y considero que es de mayor utilidad que el anterior por ser más seguro y versátil:

Sub Tabla2

VarSis

Dim mDatosTabla(5) As String, mCalifica (5) As String

Dim i As Integer

mDatosTabla(0) = "Nombre"
mDatosTabla(1) = InputBox("Nombre","Datos personales","Juan")
mDatosTabla(2) = "Apellidos"
mDatosTabla(3) = InputBox("Apellidos","Datos personales","Carrasco Pérez")
mDatosTabla(4) = "Curso y etapa"
mDatosTabla(5) = InputBox("Curso y etapa","Datos Personales","1º de E. Primaria")

 

mCalifica(0)= "ÁREA"
mCalifica(1)= "Calificación"
mCalifica(2)= "Lengua Castellana y Literatura"
mCalifica(3)= InputBox("Calificación LCL","Expediente académico","Muy positiva")
mCalifica(4)= "Matemáticas"
mCalifica(5)= InputBox("Calificación Matemáticas","Expediente académico","Muy positiva")

InicDoc

Escribir("Ficha de alumno")

SaltoLinea(1)

MacroTabla (2,3)

For i = LBound(mDatosTabla()) To UBound(mDatosTabla())
Escribir(mDatosTabla(i))
If i < UBound(mDatosTabla()) Then
SaltoCelda
End If
Next

BajaLinea(1)

SaltoLinea(1)

Escribir("Escribir a continuación el contenido pertinente")

SaltoLinea(2)

MacroTabla (2,3)

For i = LBound(mCalifica()) To UBound(mCalifica())
Escribir(mCalifica(i))
If i < UBound(mCalifica()) Then
SaltoCelda
End If
Next

End Sub

Y este el resultado (4).


Espero que, a pesar de la aparente simplicidad de los resultados, te hayas podido hacer una idea de las posibilidades que ofrecen los procedimiento de creación y cumplimentación de tablas que hemos explicado en esta entrada. Por si te interesa conocer el conjunto de macros y script que conforman este ejemplo, aquí te dejo [enlace al documento]

NOTAS.

(1) Más correcto sería decir subrutinas basadas en macros.

(2) Se activa con el botón rojo. Los datos incluidos en las variables asociadas a InputBox() lo son a modo de ejemplo, para facilitar el funcionamiento del ejemplo. Obviamente pueden ser sustituidos por los datos reales del alumno o alumna que corresponda. Además, la frase final con la que finaliza el documento implica un posterior desarrollo en formato de composición de texto similar al elaborado en otras ocasiones. Aquí únicamente se pretende ejemplificar la escritura de datos dentro de una tabla.

(3) Se activa con el botón verde. Contiene dos tablas que se complementan de forma inmediata a su creación. La segunda recoge los resultados académicos en dos áreas del currículo de E. Primaria y sólo plantea como interactiva la calificación. Esta estructura se puede modificar para ajustarla a la etapa y al número de áreas, pero como ejemplo es suficiente para nuestros objetivos actuales.

(4) No te preocupes por el efecto estético de los botones de activación de los script. Ni se borran al borrar el contenido del documento ni se imprimen; tampoco aparecen si conviertes el documento a .pdf.

miércoles, 27 de marzo de 2024

Usos. Textos

Trabajar con tablas (1)

Las tablas y las listas son, junto con el texto, los formatos más frecuente en los documentos, pero Mientras que el texto se encarga de dotar de contenido al documento, tablas y listas sirven para facilitar el visionado de determinados datos que, por su especial relevancia, precisan ser expresados de forma diferente al cuerpo de la información. En esta entrada hablaremos de las tablas y en otra posterior de las listas o listados.


Para trabajar con tablas, lo primero que tenemos que aprender es a crearlas. Para ello podemos optar por la forma más sencilla: crear una tabla activando previamente la función Grabar macro. Este es el resultado:

Sub MacroCrearTabla
VarSis
 
dim args1(3) as new com.sun.star.beans.PropertyValue
args1(0).Name = "TableName"
args1(0).Value = ""
args1(1).Name = "Columns"
args1(1).Value = 3
args1(2).Name = "Rows"
args1(2).Value = 2
args1(3).Name = "Flags"
args1(3).Value = 9

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

End Sub

Resumo las instrucciones iniciales de creación de la macro mediante la llamada a VarSis partiendo de que comprendes su significado por haberlo visto con anterioridad. Desde este supuesto paso a analizar las otras dos partes de esta macro.

Nos encontramos en primer lugar con una matriz (args1) compleja, formada por 4 pares Nombre-Valor, entre las que destacan los dos centrales que concretan el número de columnas y filas que tendrá la tabla (2). La importancia de entender esto es que nos permite manipular esos valores, directamente o mediante variables, para crear todas las estructuras de tablas que deseemos. Además también nos facilita convertir la macro en una subrutina estableciendo dos parámetros y llamarla desde un script pasando los valores como argumentos.

Para MacroCrearTabla(iCol As Integer, iFil As Integer), en las que los valores numéricos son sustituidos por el nombre de ambos parámetros nos permite trabajar con un script desde el que llamamos a la subrutina...

Sub  Tabla

Dim iTCol As Integer, iTFil As Integer

iTCol = CInt(InputBox ("Número de columnas")

iTFil = CInt(InputBox ("Número de filas")

MacroCrearTabla (iTCol, iTFil)

 End Sub

... desde el que el usuario puede definir el número de filas y columnas que tendrá la tabla cuya creación que automatiza este script.

La instrucción  dispatcher.executeDispatch(document, ".uno:InsertTable", "", 0, args1()) con la que finaliza la macro MacroCrearTabla contiene la orden de creación (InsertTable)

Como alternativa a la macro, directamente desde OOo Basic también podemos crear una tabla. 

Sub InsertarTablaA

Dim oTable As Object

oTable = ThisComponent.createInstance( "com.sun.star.text.TextTable" )

oTable.initialize(2, 3)

ThisComponent.Text.insertTextContent(ThisComponent.Text.getEnd(), oTable, False)

End Sub

En este script se diferencian dos partes: la creación de la tabla y "escritura" (trazado) en el documento. La creación de la tabla es responsabilidad de la función initialize() asociada al objeto que se referencia en la variables oTable mediante la instrucción oTable.initialize(2, 3) (3). La instrucción con la que finaliza el script (ThisComponent.Text.insertTextContent(ThisComponent.Text.getEnd(), oTable, False)) es la responsable de trazar la tabla en el documento, incluyendo su posicionamiento (getEnd()), y es similar a la instrucción de escritura de texto (4)


NOTAS

(1) Actualización de la entrada publicada el 30 de julio de 2023 con el título Writer. Creación de tablas (macro y script)

(2) El primer par permite dar un identificador a la tabla y puede tener interés si vamos a trabajar con varias tablas.

(3) Obsérvese que la función initialize(2, 3) contiene dos parámetros por lo que podremos actuar sobre ellos de igual modo que cuando creamos la tabla mediante macro.

(4) Siguiendo con lo dicho en (3), podemos transformar el script en una subrutina con tres parámetros: los dos primeros tipo integer para dar formato a la tabla y el tercero tipo string para definir la posición de la tabla al inicio o al fin del proceso de escritura del documento: InserTabla (Col As Integer, Fil As Integer, Posic As String)

Usos. Textos.

Macros de deslazamiento. (1)

Como complemento a la información sobre el desplazamiento del cursos por el documento, y aunque su utilidad práctica puede ser limitada, me ha parecido necesario recoger en esta entrada, y de forma sintética, macros de desplazamiento que afectan a la página, la línea y la letra. Estos son:



Los desplazamiento relacionados con el elemento mínimo (la letra) nos permiten avanzar o retroceder de posición respecto a este elemento. El código común a ambos movimientos se concreta como sigue:

dim args1(1) as new com.sun.star.beans.PropertyValue
args1(0).Name = "Count"
args1(0).Value = 1
args1(1).Name = "Select"
args1(1).Value = false

  • Para [avanzar de posición] respecto a una letra podemos utilizar esta orden complementando a la estructura anterior:

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

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

El movimiento respecto a una palabra se realiza mediante dos instrucciones similares:

dispatcher.executeDispatch(document, ".uno:GoToNextWord", "", 0, Array())

dispatcher.executeDispatch(document, ".uno:GoToPrevWord", "", 0, Array())

Aunque el avance respecto a la línea ya la empleamos, resumo ahora el código necesario. Primero el común, que, como ves, es el mismo que para el desplazamiento respecto a la letra...

dim args1(1) as new com.sun.star.beans.PropertyValue
args1(0).Name = "Count"
args1(0).Value = 1
args1(1).Name = "Select"
args1(1).Value = false

... que se complementa con esta orden para avanzar hacia la [línea siguiente]

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

...y hacia la  [línea anterior]

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

Finalmente, el desplazamiento página a página se resuelve con estas dos instrucciones:

dispatcher.executeDispatch(document, ".uno:PageDown", "", 0, Array())

dispatcher.executeDispatch(document, ".uno:PageUp", "", 0, Array()) 


NOTA

(1) Entrada actualiza a partir de una entrada publicada el 13 de octubre de 2023, titulada Writer. Desplazamiento por el documento.