Trabajar con listas.
Uno de los tipos específicos de texto que tenemos que crear con cierta frecuencia son los listados, bien como documentos en si mismos, bien como elementos de un documento más amplio. Para hacerlo mediante teclado (que suele ser lo común) existen tres opciones básicas: crear la lista desde cero, copiar y pegar los ítem recurriendo a un documento externo que contiene la lista maestra o utilizar esa lista maestra como plantilla y, al contrario que en los casos anteriores, eliminar los ítem que no interesen. Aunque la tercera fórmula es el modo de trabajo que más se acerca al objetivo de la automatización, todas ellas, en realidad, están muy lejos que acercarse a este objetivo. Usar macros y script (OOo Basic) es la única forma en que realmente se facilitar la tarea.
Aunque no siempre es posible ni conveniente utilizar macros y/o script para automatizar la creación de un listado (1), hay razones para pensar que son muchas las circunstancias en las que sí merece la pena crear procedimientos informatizados para ayudarnos en la tarea. esto es especialmente cierto cuando contamos con un listado previo y relativamente estable y más aun si ese listado es de cierta extensión. Ejemplos hay muchos: listado del alumnado con NEAE, relato de los asistentes a una reunión de la UO (2), listado de indicadores de evaluación a incluir en una PTI...
En cualquier caso, y para lo que ahora nos importa, disponer de procedimientos de generación informatizada de listados nos va a ayudar a simplificar el trabajo, aunque requiera uno previo.
No me voy a detener demasiado en el aspecto formal de la creación de un listado, que podemos resolver mediante el uso de tablas o mediante la activación de las marcas del ítem de lista (vg. un número índice o una bolita) por medio de una macro. Pero tampoco quiere dejar de explicar cómo hacerlo, así que dedicaremos el inicio de esta entrada a explicar esta forma de trabajo mediante macros simples y script.
Como sabemos, las listas son de dos tipos genéricos: alfanuméricas y gráficas. Las dos macros simples que las generan son las siguientes:
Alfanumérica:
dim args1(0) as new com.sun.star.beans.PropertyValue
args1(0).Name = "On"
args1(0).Value = true
dispatcher.executeDispatch(document, ".uno:DefaultNumbering", "", 0, args1())
Gráfica (en este caso de bolita)
dim args1(0) as new com.sun.star.beans.PropertyValue
args1(0).Name = "On"
args1(0).Value = Valor
dispatcher.executeDispatch(document, ".uno:DefaultBullet", "", 0, args1())
Ambas trabajan con argumentos booleanos (arg().Value), así que la conversión de estas macros simples en subrutinas para ser empleadas desde un script, supone implementar un argumento (variable) de tipo Boolean: sub ListaSimple (Valor As Boolean) que deberemos incluir en la llamada a la subrutina como en este ejemplo: ListaSimple(True). Cuando queramos finalizar el listado, deberemos llamar de nuevo a la subrutina y cambiar el argumento a False.
Además de este código, también necesitamos el código (macro o script) de escritura y el salto de línea al finalizar el ítem...
dispatcher.executeDispatch(document, ".uno:InsertPara", "", 0, Array())
Podemos anidar listas (e ítem) mediante el uso de tabulador, generando un incremento del sangrado que facilita la estructuración de la lista en ítem principal e ítem secundario. Para ellos haremos uso de la misma macro-subrutina de escritura, pasando como argumento el carácter especial Chr$(9). A continuación te muestro el script que nos permite generar una lista (los inicios de la misma) que contiene otra anidada. Hacerla más amplia y funcional es cosa de escribir más líneas de código:
Sub CrearLista
VarSis
ListaSimple(True)
Escribir("Listado de alumnos con NEE")
SaltarLinea
ListaSimple(False)
Escribir(Chr$(9))
ListaSimpleNum(True)
Escribir("Jaime Ortega López")
End Sub
... y este es el resultado. Simple por haberme ahorrado esfuerzos, pero suficiente para explicar lo que me interesa.
Sub Semana
VarSisDim DiasSemana(6) As StringDim i As Integer
DiasSemana(0) = "Lunes"DiasSemana(1) = "Martes"DiasSemana(2) = "Miércoles"DiasSemana(3) = "Jueves"DiasSemana(4) = "Viernes"DiasSemana(5) = "Sábado"DiasSemana(6) = "Domingo"
ListaSimple(True)Escribir("Días de la semana")SaltarLineaListaSimple(False)Escribir(Chr$(9))ListaSimpleNum(True)
For i = LBound(DiasSemana()) To UBound(DiasSemana())Escribir(DiasSemana(i))If i < UBound(DiasSemana()) ThenSaltarLineaEnd IfNext
End Sub
Como puedes observar, este script se divide en cuatro partes:
- En la primera se llama a VarSis que nos permite trabajar con macros y se declara una matriz (DiasSemana(6)) y una variable contador (i)
- En la segunda se asignan valores a cada elemento de la matriz
- En la tercera se llama a un conjunto de macros para escribir la primera línea del código, saltar a la línea siguiente, generar un espacio de tabulación e implementar el formato numérico de la lista (3)
- La cuarta parte es la de mayor complejidad y novedad. En síntesis recorremos la matriz con un bucle For utilizando como referencias los valores inicial y final de la estructura de la matriz mediante las funciones LBound() y UBound() y llamamos a la macro de escritura asignando como parámetro cada un de los elementos de la matriz. El condicional If evita que se escriba un elemento de la lista innecesario, si bien su función inmediata es escribir los elementos numerales del listado mediante la macro SaltarLinea.
Muestro a continuación el resultado. No parece gran cosa, pero que supone la escritura automática de una lista:
Nos falta dar un paso más que básicamente consiste en dar la posibilidad de automatizar la escritura de una lista resultante de la selección de ítem de otra lista. Viene a ser el equivalente a trabajar sobre un documento-base que contiene a lista completa de la que vamos borrando los elementos que no nos interesan. De este modo conseguimos generar listas personalizadas, con todos los posibles usos prácticos que podemos intuir (4)
Este es el script. Por simplicidad sustituyo la escritura en el documento por el mero visionado de los elementos de la lista mediante MsgBox, pero el principio de funcionamiento del script no supone una variación sustancial. Esta simplificación permite que nos centremos en lo fundamental del funcionamiento del script.
Sub MatrizSemana
Dim DiasSemana(6) As String
Dim MisDias () As String
Dim Dia As Integer
Dim i As Integer, b As Integer
DiasSemana(0) = "Lunes"
DiasSemana(1) = "Martes"
DiasSemana(2) = "Miércoles"
DiasSemana(3) = "Jueves"
DiasSemana(4) = "Viernes"
DiasSemana(5) = "Sabado"
DiasSemana(6) = "Domingo"
b = 0
For i = LBound(DiasSemana()) To UBound(DiasSemana())
Dia = MsgBox (DiasSemana(i),4,"MIS DIAS")
If Dia = 6 Then
ReDim Preserve MisDias(b)
MisDias(b) = DiasSemana(i)
b=b+1
End If
Next
MsgBox "Número de días seleccionados: " & CStr(UBound(MisDias()) + 1)
For i = LBound(MisDias()) To UBound(MisDias())
MsgBox MisDias(i)
Next
End Sub
- El contenido de la variable de paso Dia se asocia a la función MsgBox() para que el usuario seleccione (comandos Sí/No) los ítem que le interesen de la matriz principal, la cual se usa como información en el cuerpo del MsgBox:
Dia = MsgBox (DiasSemana(i),4,"MIS DIAS")
- El condicional que sigue permite condicionar la incorporación del dato en función de la respuesta anterior (Sí). De no cumplirse esa condición no se produce el paso del valor a la matriz-destino: MisDias(b) = DiasSemana(i)
- Pero, además, en el cuerpo de ese condicional, y antes de la asignación antes señalada, redimensionamos la matriz-destino, manteniendo su contenido (ReDim Preserve MisDias(b)). Esto es fundamental para controlar que la matriz-destino no incluya elementos no deseados (posiciones vacías).
- Nos debemos fijar ahora en el uso del contador b: hemos asignado un valor inicial antes del inicio del bucle (b = 0), lo utilizamos como índice de la matriz de destino en sustitución del contador i que utilizamos como índice en la matriz-origen, tanto para el redimensionado como en la asignación, y finalmente y también dentro del condicional, incrementamos su valor como contador (b=b+1).
- El resultado de esta estructura es que el usuario selecciona/rechaza cada uno de los ítem de la matriz-origen (7), pero sólo se incorpora a la matriz-destino el ítem seleccionado. El MsgBox que sigue permite comprobar el número de elementos de la matriz-destino una vez finalizado el proceso de selección (MsgBox "Número de días seleccionados: " & CStr(UBound(MisDias()) + 1)) (8)
NOTAS.
(1) No veo la posibilidad ni la conveniencia de hacerlo cuando la lista es sencilla y no partimos de una definición clara de los ítem. En esos casos el trabajo de crear el procedimiento informatizado puede ser mayor que el que haremos escribiéndola directamente.
(2) Este en realidad es un ejemplo dudoso, ya que se puede incluir el listado completo en la plantilla del acta de la RUO y proceder simplemente suprimiendo los no asistentes. No obstante sí puede ser de interés automatizar la elaboración del acta, con lo que la inclusión del listado de asistentes será parte del proceso, aunque no necesariamente si partimos de un documento-modelo que contenga la lista de componentes de la UO.
(3) Todo ello reproduce el modelo de uso explicado al inicio de esta entrada.
(4) La complejidad del contenido depende especialmente de los contenidos de la propia lista: desde una sencilla y de pocos elementos, hasta una de muchos componentes, como puede ser el listado de las pautas DUA o de los criterios de evaluación de un área curricular.
(5) Eliminar la escritura en el documento permite esta reducción del contenido del script. En otro caso sería necesario, cuanto menos, incluir una llamada a la subrutina de escritura y si este proceso lo realizáramos empleando macros y manteniendo la visualización que hemos generado en las formas anteriores, implicaría el añadido de los elementos que utilizamos en el script anterior.
(6) En este script no se llama a VarSis por no ser necesario para el funcionamiento esperado. De querer utilizar macros para escribir en el documento, deberíamos incluirlo.
(7) El procedimiento de ir seleccionado ítem por ítem hace que sea un tanto lento, y más aun si el número de ítem es elevado. Es posible salir de bucle mediante la instrucción Exit asociada a un condicional, y también es posible que existan formas de condicionar la presentación o no de determinados ítem de la matriz-origen. La primera fórmula no la uso en este caso y la segunda, en este momento desconozco cómo implementarla.
(8) Dado que es ésta su única función es perfectamente posible prescindir de él en la formulación final del script, pero es muy útil durante la fase de pruebas, motivo por el cual lo he mantenido. Obsérvese que hago uso de la función UBound(MisDias()) para conocer el valor de posición del último elemento de la matriz-destino, añadiendo +1 para que el resultado sea directamente comprensible (el número exacto de elementos de la matriz-destino). Esto es debido a que, como sabemos, el primer elemento de una matriz se identifica como 0.