Mostrando entradas con la etiqueta Writer. Mostrar todas las entradas
Mostrando entradas con la etiqueta Writer. Mostrar todas las entradas

lunes, 16 de diciembre de 2024

Documentos. Modelo básico

Modelo básico de docap (b)

Hay una diferencia entre este segundo modelo y [el anterior] en la fase de preparación, además de la que deriva de la forma diferente de manejar el servicio Writer: dado que ahora trabajamos con un documento creado (frente al documento en blanco del modelo anterior), no sólo tenemos que acceder a dicho documento (y no sólo activar el servicio Writer), sino que también tenemos que tener preparado previamente ese documento. Todo esto supone que este segundo modelo de docap resulte sensiblemente más complejo (1).


Para empezar crearé el soporte Calc y el documento Writer, que ubicaré en un subdirectorio de fácil acceso (2). En mi caso creo un subdirectorio en una unidad USB-unidad D, al que llamo Acta (3) e incluyo en ella dos documentos: GestorActa (Calc) y ActaModelo (Writer).

El segundo paso consiste en crear el formulario en GestorActa y asociar los controles a las celdas, igual que en el docap-modelo anterior. También creo los módulos Modulo1 Modulo2 desde el IDE para contener los script que crearé más tarde.

Aunque puedo seguir trabajando en el script Main con las instrucciones que darán acceso a las celdas que contienen los datos, opto por trabajar sobre el documento-modelo, formateándolo y generando las posiciones de los marcadores. Este podría ser el resultado:


Sobre este documento, y a modo de ejemplo, posiciono tres marcadores (Insertar | Marcador) (4) que llamados respectivamente mcdAsisten, mcdTemas y mcdFecha donde se infiere por su nombre. Finalizo la preparación del documento guardándolo y creando una copia de seguridad (5).

Una vez que hemos creado el documento-modelo,  volvemos a trabajar sobre GestorActa para generar el código OOo Basic. En primer lugar, desarrollo el procedimiento de acceso al contenido introducido por el usuario mediante el formulario (6). Incluyo la declaración de variables y matrices (algunas las explicaré más adelante):

'Variables
Dim oHoja As Object, oCelda As Object
Dim mDatos() As String, mCeldas() As String, mMarcadores() As String
Dim n As Integer, i As Integer
Dim sAsisten As String

'Acceso a datos

oHoja = ThisComponent.getSheets().getByName("Hoja1")

n = 5
ReDim mDatos(n)

mCeldas= Array("I1","I2","I3","I4","I5","I6")

mMarcadores() = Array("mcdAsisten","mcdTemas","mcdFecha")

For i = 0 To UBound(mDatos())
oCelda = oHoja.getCellRangeByName(mCeldas(i))
mDatos(i) = oCelda.getString()
Next

Primero accedo a la Hoja1 del documento Calc (oHoja = ThisComponent.getSheets().getByName("Hoja1")) y después de redimensionar la matriz mDatos (ReDim mDatos(n)) en función del número de elementos de la lista (n = 5), cargo el contenido en dicha matriz mediante un ciclo For (For i = 0 To UBound(mDatos())) según el procedimiento ya conocido.

oCelda = oHoja.getCellRangeByName(mCeldas(i))
mDatos(i) = oCelda.getString()

Previamente he dado contenido a la matriz mCeldas() (mCeldas= Array("I1","I2","I3","I4","I5","I6")) para facilitar el funcionamiento del bucle (oCelda = oHoja.getCellRangeByName(mCeldas(i))). De este modo los datos contenidos en las citadas celdas pasan a la matriz mDatos() y quedan disponibles para su manejo desde el código (mDatos(i) = oCelda.getString()).

Además adelanto trabajo dando contenido a la matriz mMarcadores() (mMarcadores() = Array("mcdAsisten","mcdTemas","mcdFecha")) que necesitaré más adelante.

Dado que en este docap también inciden los mismos condicionantes que en el docap anterior, tampoco aquí me detendré en desarrollar la fase procesamiento más allá del mínimo que exige la diferenciación de los tres campos que identificados por asociación con los tres marcadores implementados en el documento. Este mínimo se concreta en el bucle que asigna a la variable sAsisten la concatenación de los cuatro primeros componentes de la matriz mDatos() (sAsisten = sAsisten & Chr(13) & mDatos(i)) que corresponden a los posibles asistentes a la reunión:

For i = 0 To 3
If mDatos(i) = "" Then
sAsisten = sAsisten
Else
sAsisten = sAsisten & Chr(13) & mDatos(i)
End If
Next

En él, el condicional anidado If (If mDatos(i) = "" Then) impide que se generen saltos de línea en caso de ausencia de alguno de los cuatro potenciales asistentes (Asisten = sAsisten). 

Además incluyo en Main el código necesario para acceder al documento-modelo...

Dim sRutaAcceso As String, sRutaGuardar As String
Dim mOpciones(1) As New "com.sun.star.beans.PropertyValue"
mOpciones(0).Name = "AsTemplate"
mOpciones(0).Value = True

Dim oDocModelo As Object
sRutaAcceso = ConvertToUrl("D:/ACTA/ActaModelo.odt")
oDocModelo = StarDesktop.loadComponentFromURL( sRutaAcceso, "_blank", 0, mOpciones())

... según el procedimiento ya explicado en [esta entrada] en la que se trata este tema con más detalle. Como característica específica decir que en este caso abrimos dicho documento en modo plantilla

Dim mOpciones(1) As New "com.sun.star.beans.PropertyValue"
mOpciones(0).Name = "AsTemplate"
mOpciones(0).Value = True

... lo que facilita mantener sin modificar el propio documento-modelo, evitando así posibles errores en el manejo de dicho documento, como puede ser el borrado accidental de los marcadores o la sustitución de dicho documento por el que deriva del uso del docap, a consecuencia de una grabación descuidada del documento resultante.

Finalizamos Main con la llamada a la subrutina de escritura del acta, tantas veces como marcadores están disponible.

Acta(oDocModelo,sAsisten,mMarcadores(0))
Acta(oDocModelo,mDatos(4),mMarcadores(1))
Acta(oDocModelo,mDatos(5),mMarcadores(2))

Esta subrutina se limita a ejecutar la escritura del contenido pasado mediante el parámetro Texto (por ejemplo, sAsisten), en la posición que indica el parámetro Marcador (por ejemplo mMarcadores(0)), habiendo previamente accedido al documento abierto (oDocModelo = StarDesktop.loadComponentFromURL( sRutaAcceso, "_blank", 0, mOpciones())), paro lo cual debemos pasar también como parámetro (Modelo As Object) dicho modelo (oDocModelo) (7)

Sub Acta(Modelo As Object,Texto As String,Marcador As String)
Dim oMarcador As Object
oMarcador = Modelo.getBookmarks().getByName(Marcador)
oMarcador.getAnchor.setString(Texto)
End Sub

Documento. Desde sus enlaces puedes descargar [GestorActa] y [ActaModelo]. Recuerda que debes guardarlos en una unidad externa (D) dentro de un subdirectorio (ACTA). Si optas por otra ubicación deberás modificar la instrucción sRutaAcceso = ConvertToUrl("D:/ACTA/ActaModelo.odt") para ajustarla a la nueva ubicación.

NOTAS

(1) De lo que se deriva una recomendación: si no es estrictamente necesario, siempre será preferible trabajar con el modelo de docap más simple.
(2) Aunque es opcional, yo te recomiendo trabajar en estos casos con un soporte de almacenamiento externo. Por motivo de seguridad y confidencialidad así lo hago yo en este ejemplo, dado que quedará publicado en la nube. De este modo también te será más sencillo replicar el funcionamiento de este docap: es suficiente con seguir los mismos pasos que te explico en el texto.
(3) Como puede comprender, en este caso no es posible crear un docap totalmente independiente de un objetivo concreto de trabajo, aunque éste puede ser el que tu necesites. Por ello deberemos trabajar sobre un supuesto. Este supuesto es, en este caso, la cumplimentación de determinados apartados de un acta, por ejemplo de la UO. No por ello deja doporte para el objetivo de semi-automatizar la cumplimentación del acta.
(4) En [esta entrada] se explica con más detalle cómo proceder. 
(5) Esta copia garantiza disponer del documento tal y como fue creado, pensando en que pueda surgir alguna dificultad en el proceso, dada la sensibilidad de los marcadores al borrado accidental. Después veremos que nos conviene trabajar con una plantilla del documento para que el original siempre esté disponible.
(6) El mismo código que creamos en el docap-modelo anterior, como podrás comprobar.
(7) Esta no es la única forma de desarrollar ambos subprocesos, pero tiene la ventaja de diferenciar la fase de acceso al documento-modelo de la escritura del contenido propiamente dicha. Otra opción podría haber sido diferenciar la fase de acceso y manejo de los datos (Main) de la de acceso al documento y escritura. Una tercera fórmula sería diferenciar esa subrutina en dos partes: la primera se encargaría de acceder al documento-modelo y la segunda de escribir en él.

domingo, 26 de mayo de 2024

OOo Basic. Interface

 Diálogo (b). Etiqueta

Aunque un Formulario también puede contener etiquetas, al estar creado sobre el documento, es fácil suplir su función por la mera escritura de su contenido sobre el propio documento. En el caso del Diálogo esto no es posible, así que no queda otro remedio que utilizarlas.


En el Diálogo una etiqueta puede cumplir varias funciones, según cómo se configure: puede servir como información sobre el control que sigue, pero también puede considerarse un elemento informativo sobre qué se solicita con el diálogo, sobre el proceso a seguir o sobre los resultados obtenidos. En todos estos (segundos) casos, la etiqueta es mucho más que un mero auxiliar de otro control, asemejándose a las funciones de información que son propias de MsgBox (1)

Generalmente la etiqueta es un control estático, lo que significa que el contenido que le demos en la fase de construcción del diálogo es que que va a mantener en todo momento. En este supuesto el uso de Etiqueta se limita a su implementación en la fase de creación del Diálogo, con lo que casi no deberíamos decir aquí nada más (2). Y de hecho podríamos funcionar con este planteamiento incluso aunque necesitemos aportar información diferente (3) a lo largo del script (4); en este caso, aunque no es precisamente ejemplo de ahorro de recursos y de simplicidad, es posible crear varios diálogos cada uno con su(s) etiquetas, y en cada una con su propio texto. Pero también podemos modificar el contenido o texto que mostrar; en este caso ya no podemos hablar de la etiqueta como elemento estático. Veremos ahora cómo.

Para que una etiqueta presente un contenido textual diferente necesitamos acceder a su modelo de objeto, lo cual nos permite modificar algunas de sus características, incluyendo (para lo que nos interesa ahora) el contenido textual de la propia etiqueta.

Dim oEtq As Object

Dim sEtqConten As String 

sEtqConten = "Este es el texto que mostrará la etiqueta" 

oEtq = oDlg.detControl()"etqInicio")

With oEtq.getModel

.Label = sEtqConten

 End With

Este segmento de código ilustra el modo en que podemos modificar dinámicamente el contenido textual de Etiqueta y constituye la base para que este control deje de ser necesariamente estático. Mediante la manipulación del contenido de una variable (sEtqConten) y el acceso al modelo de objeto (y su atributo Label) podemos implementar el texto que deseemos sin necesitar crear tantos diálogos y etiquetas como información queramos dar. Esto es válido para personalizar dicho contenido, para modificarlo en función de determinadas condiciones o para mostrar sobre el mismo diálogo una sucesión de contenido informativo diferente.

En el último documento que te proporciono ejemplifico una secuencia de mensajes simples sobre un único diálogo que se presentan de forma sucesiva mediante un bucle (5).

Documentos:

NOTAS

(1) Cuando no se usa como función (MsgBox()), capacidad que no tiene la etiqueta.

(2) De hecho difícilmente estaría justificado dedicarle una entrada en este blog.

(3) Segundo(s) supuesto(s) del párrafo anterior: notas informativas sobre el proceso a seguir e información sobre resultados del procesamiento de datos. Esta segunda función no es muy frecuente, ya que lo normal es trasladar los resultados el propio documento sobre el que trabaja el script.

(4) Los dos primeros documentos son ejemplos de etiquetas estáticas, única (el primero) y múltiple (el segundo). Perfectamente podríamos hacer uso de MsgBox. Aunque usar etiquetas tiene ventajas de formato sobre MsgBox, en lo fundamental no nos aportan mucho más. Aunque esas ventajas pueden ser suficientes para preferirlas.

(5Para que se produzca el cambio de saludo es necesario cerrar el Diálogo tantas veces como ciclos tiene el bucle (3)

domingo, 19 de mayo de 2024

OOo Basic. Interface.

Formularios (b)

Analizo ahora el acceso a los controles de uso más frecuente en un formulario desde OOo Basic, esté creado éste sobre un documento Writer o sobre una hoja de cálculo Calc. Esta entrada complementa, pues, la [entrada anterior] en la que explico la creación del formulario sobre el documento y el acceso a éste mediante código OOo Basic, este sí diferentes según el servicio (Calc o Writer) sobre el que esté implementado.




Los controles de uso más frecuente en un formulario son cuatro (1): Caja de texto, Cuadro de lista, Botón de opción y Casilla (de verificación). Los dos primeros para la entrada de datos y los dos últimos para facilitar la elección de una posible opción de respuesta.

Como ya sabemos, todos los controles de formulario deben ser implementados en el documento-soporte de forma manual (ver [aquísobre la implementación de un formulario Formulario), pero además necesario (o la menos conveniente) conformar la apariencia y forma de funcionamiento de cada uno de esos controles de forma específica. Para ello deberemos acceder a Propiedades del control, opción disponible a partir de la ventana emergente que activamos mediante Selección del control -> Clic derecho sobre el control seleccionado. Una vez dentro de este menú de opciones, podremos configurar nuestro control.

El control Cuadro de texto se comporta funcionalmente como un InputBox(); no obstante presenta características y posibilidades de uso diferentes que las que ofrece InputBox() (2). Para acceder a este control y a su contenido crearemos el código siguiente:

Dim oTxtNombre As Object

Dim sDato As String

 oTxtNombre = oFormulario.getByNa.me("txtAlNombre")

 sDato = oTxtNombre.Text

  • Primero creamos dos variables, la primera (oTxtNombre ) de tipo Object (recuerda que un control es un objeto en LibreOffice) y la segunda (sDato) de tipo String.
  • El paso siguiente es acceder al objeto control (en este caso) por su nombre (una de las opciones que tenemos cuando configuramos el control) mediante la siguiente instrucción: oTxtNombre = oFormulario.getByName("txtAlNombre")
  •  Finalmente, recurriendo al atributo Text del control, accedemos al contenido introducido por el usuario. Asignamos este contenido a la variable String creada al inicio de del código (sDato = oTxtNombre.Text)

El control Cuadro de lista se diferencia del anterior por sustituir la entrada de texto de escritura libre por una lista de datos, presentados como opciones de respuesta para la elección del usuario. Este listado puede crearse directamente desde Propiedades del control -> General -> Entradas de la lista o desde Propiedades del control -> Datos -> Tipos de contenido de la lista opción Lista de valores. Esta segunda forma también permite asociar el control a una tabla, una consulta o a otras opciones de base de datos.

Para acceder al control Cuadro de lista se sigue el mismo procedimiento que para hacerlo a Cuadro de texto, pero no así para el acceso al dato seleccionado por el usuario. Observa el código siguiente:

Dim oCurso As Object, oCursoVista As Object
Dim sCurso As String

oCurso =  oFormulario.getByName("curso")
oCursoVista = ThisComponent.getCurrentController.getControl( oCurso )
sCurso = oCursoVista.getSelectedItem()
  • Primero declaramos dos variables Object para acceder a los objetos control (oCurso) y listado del control (oCursoVista) y una tercera variable, esta de tipo String (sCurso)
  • El uso de las dos variables Object es el siguiente:
    • Mediante la primera (oCurso) accedemos al control como tal (oCurso =  oForm.getByName("curso"))
    • Y mediante la segunda (oCursoVista) a su listado de opciones (oCursoVista = ThisComponent.getCurrentController.getControl( oCurso ))
  • Posteriormente asignamos la opción seleccionada (método getSelectedItem()) a la variable String, previamente declarada (Dim sCurso As String) haciendo uso de ese método (sCurso = oCursoVista.getSelectedItem())
El control Botón de opción es en realidad un conjunto (de al menos dos controles del mismo tipo vinculados entre sí; ambos ofrecen al usuario la posibilidad de elegir uno de ellos como opción seleccionada (el o los otros se descartan), por lo que el conjunto presenta un comportamiento similar al del Cuadro de lista en el que el usuario opta por una de las opciones que se le presentan), aunque en su apariencia formal y su funcionamiento son muy diferentes.

También es diferente el modo en que se accede a la opción seleccionada, requiriendo Botón de opción un manejo similar al que hacemos del valor que devuelve la función MsgBox() (3).

        Dim oBtn1 As Boject, oBtn2 As Object
Dim sSexo As String
oBtn1 = oFormulario.getByName("btn1")
oBtn2 = oFormulario.getByName("btn2")
If oBtn1.State() Then
sSexo = "Niño"
End If
If oBtn2.State() Then
sSexo = "Niña"
End If
MsgBox "Sexo": " & sSexo

El acceso al "contenido" en Botón de opción es en realidad la captura de su pulsación por el usuario (oBtn1 = oFormulario.getByName("btn1")), y se requieren tantas variables como botones de opción contenga nuestro conjunto de opciones. Por ejemplo, en este caso, sólo dos (oBtn1 y oBtn2): el primero capturar la pulsación del botón btn1 (oBtn1 = oFormulario.getByName("btn1")) y el segundo la del botón btn2 (oBtn2 = oFormulario.getByName("btn2"))

Al hacerlo capturamos también sus métodos y propiedades, en concreto el método  State(), que presenta dos opciones (0|1), dado que es de tipo Boolean. Por ello es posible valorar el estado del botón mediante el condicional If. En función del resultado del análisis del estado (State()) de los diferentes botones que componen ese conjunto, asignamos un valor u otro a una segunda variable (en nuestro caso sSexo que es de tipo String) que es la que contendrá la información relevante para el desarrollo del script. En nuestro ejemplo se trata de determinar el sexo del alumno (sSexo="Niño" vs. sSexo="Niña"y de informar de ello mediante MsgBox (MsgBox "Sexo": " & sSexo)

Finalmente el control Casilla (de selección o de verificación) se diferencia de Botón de opción en su forma externa (se representa como un cuadradito en vez como círculo) pero se asemeja en el código necesario para acceder al control y a su estado (de nuevo el método State()). 

Otra diferencia entre ambos es que Casilla no es opcional-excluyente cuando se presenta en agrupamientos, lo que implica que el usuario puede marcar cada uno de estos controles de forma independiente, cosa que no sucede con los botones. De hecho una presentación posible de Casilla es como control único de confirmación del cumplimiento de una condición (Vg. ¿Es correcta esta contraseña?). Otra es, como dije, formando agrupamientos, como en el ejemplo que sigue (4).

        Dim oCasilla1 As Object, oCasilla2 As Object, oCasilla3 As Object
        Dim iPuntos As Integer

iPuntos = 0 

        oCasilla1 = oFormulario.getByName("Casilla1")

If oCasilla1.State() = 0 Then

 iPuntos = iPuntos + 1

End If

En este script, las tres casillas pueden ser seleccionadas independientemente una de otra. De hecho la respuesta correcta implica no seleccionar la primera y sí las otras dos. 

Por lo que se refiere al código de acceso al objeto Casilla como el tratamiento de su estado (State()) es igual que el Botón de opción, como puedes observar comparando ambas instrucciones.

Documentos. Ambos enlaces permiten la descarga del formulario sobre Writer y sobre Calc. Se trata de ejemplificar el uso y [acceso a los formularios], diferente en función del servicio, y a los controles de uso más frecuente (los tratados en esta entrada).


NOTAS 

(1) LibreOffice cuenta con un listado de controles de formulario mucho más amplio, pero estos cuatro cubren la mayoría de las necesidades que buscamos satisfacer con un formulario, de ahí que sean los de uso más frecuente y, por tanto, los que más interés tienen para la creación de un docap basado en Formulario.

(2El manejo de Cuadro de texto requiere el mismo procedimiento de acceso que cualquier otro control de formulario, por lo que no es factible trabajar con él como con InputBox(). En términos de funcionalidad, Cuadro de texto permite opciones de configuración que no están disponibles en InputBox() (que en esto es muy limitado); destaco por su utilidad la posibilidad de configurarlo multirrenglón, además de los formatos de texto (incluido tamaño de letra). Estas opciones de configuración permiten un uso muchos más amigable y funcional como interface, si bien requiere un trabajo previo de configuración desde Propiedades del control.

(3) También en este caso deberemos tratar el valor devuelto mediante un condicional If.

(4) Se trata de un fragmento del script real. En él se ejemplifica el acceso a uno de los tres controles Casilla y a su posterior tratamiento mediante el condicional If. El script completo está disponible en el documento que ejemplifica el uso de los controles que se explican en esta entrada.

jueves, 16 de mayo de 2024

OOo Basic. Interface.

Formularios (a)

Además de las formas simples de interface (MsgBox e InputBox), LibreOffice cuenta con otros dos recursos de interface: los formularios y los cuadros de diálogo




Los formularios son medios para facilitar la interacción usuario-programa, empleados fundamentalmente en la fase Input. A diferencia del cuadro de diálogo (en adelante, Diálogo, por brevedad), el formulario se puede emplear tanto como funcionalidad (1como asociado a a un script; en ambos casos, el primer paso consiste en crear el formulario (funcionalidad) desde el documento, sea este un documento Writer o desde Calc.




En esta entrada trataré sobre el acceso al formulario mediante código OOo Basic, útil para trabajar con Writer, Calc e Impress. Los formularios de Base (base de datos) quedan fuera de nuestros objetivos por su especificidad.

El primer paso es, como dije antes, es crear el formulario desde el documento. Es posible que esta funcionalidad no está directamente disponible (2), por lo que necesitaremos activar las opciones FormularioVer | Barra de herramientas | Diseño de formularios (que muestra sus controles) y Ver | Barra de herramientas | Controles de formularios, que muestra las herramientas de los Controles. A partir de aquí lo que debemos hacer es seleccionar el icono Modo diseño... (3)



Una vez creado el formulario, para trabajar sobre él mediante OOo Basic deberemos trabajar desde el IDE para acceder a la capa gráfica (getDrawPage()), que es donde se sitúan los formularios (4). 

El recorrido que deberemos hacer para acceder a un formulario depende del soporte (o servicio) en el que esté creado: no es lo mismo trabajar desde Writer que hacerlo desde Calc.

Un script que nos permita acceder a un formulario creado en un documento Writer requiere realizar el siguiente recorrido, en el que se diferencian cuatro pasos, que precisan contar con una serie de variables de tipo Object (5): 

Dim oDocumento As Object, oCapaDib As Object, oForms As Object, oForm As Object

  • Paso 1. Acceso al documento: oDocumento = ThisComponent
  • Paso 2. Acceso a la capa gráfica: oCapaDib = oDocument.getDrawPage()
  • Paso 3. Acceso al conjunto de formularios: oForms = oCapaDib.getForms()
  • Paso 4. Acceso al formulario concreto por el índice o por el nombre: 
oFormulario = oFormularios.getByIndex()               -> Acceso por el índice

oFormulario = oFormularios.getByName("frmActua")  -> Acceso por el nombre


El acceso a un formulario creado sobre Calc requiere también seguir una serie de pasos (cinco) que se basan en un conjunto de variables tipo Object por las mismas razones que expusimos antes (ver nota 5)

Dim oDocumento As Object, oHojaActiva As Object, oPaginaDibujo As Object
Dim oFormularios As Object, oFormulario As Object

 Los pasos a seguir son los siguientes:
  • Paso 1. Acceso al documento: oDocumento = ThisDocument
  • Paso 2. Acceso a la hoja activa: 
oHojaActiva = oDocumento.getCurrentController.getActiveSheet()

  • Paso 3. Acceso a la capa gráfica: oPaginaDibujo = oHojaActiva.getDrawPage()
  • Paso 4. Acceso al conjunto de formularios: oFormularios = oPaginaDibujo.getForms()
  • Paso 5. Acceso al formulario concreto, el cual puede ser por índice o por el nombre:

oFormulario = oFormularios.getByIndex()                   -> Acceso por el índice 
oFormulario = oFormularios.getByName(""frmCalcEj")      -> Acceso por el nombre


Podemos 
 considerar lo anterior como primera fase del proceso, que finaliza con el acceso a los contenidos que introduce el usuario en los controles del formulario. Dedicaremos a ello la entrada siguiente.

NOTAS

(1) Por funcionalidad entiendo cualquier recurso que puede ser desarrollado desde la interface general del servicio (Writer, por ejemplo), sin necesidad de acceder al IDE. En Writer los formularios se crean en la capa "Dibujo" del documento directamente desde éste. Para crear un Diálogo es necesario acceder al IDE y crearlo específicamente de forma directa. Desde esta perspectiva el formulario es un objeto más accesible y simple que un diálogo.

(2) Es posible que esta sea una de las causas de su escaso uso. Contribuye a ello que en los documentos prescriptivos (que no hacen otra cosa que seguir la costumbre consolidad por el uso) se empleen tablas como base para simular la apariencia de formulario.

(3) Este procedimiento implica activar el icono de la barra Controles de formulario. Este mismo icono está también disponible en la barra del Diseño de formulario. Activarlo también supone acceder a la definición del formulario y a otras utilidades, incluyendo la introducción de campos (comando Añadir campo), que también activa la barra Controles de formulario.

(4) Tanto en Writer como en Calc, los formularios se ubican en la capa gráfica ("de dibujo"), que se superpone a la capa en la que escribimos en el documento (en Writer) o en la que se encuentran las celdas (en Calc)

(5) Tanto el documento, como la capa gráfica y los formularios son objetos, dado que LibreOffice es un programa creado dentro del paradigma de la Programación Orientada a Objetos (POO)

miércoles, 8 de mayo de 2024

Recursos. Dictamen.

Dictamen 2024. Una propuesta de automatización.

Comenté en [esta entrada] el documento-modelo de informe de la Consejería de Educación asturiana de 2024 y [en esta otra] hice algunas propuestas (1) para su adaptación y uso por parte de los SEO. Además en [Usos] he estado desarrollando la explicación de diferentes estrategias para complementar los datos solicitados en las tablas tanto del informe como del dictamen (2), pero aun no he expuesto una propuesta de docap para automatizar la cumplimentación del modelo de dictamen, así que ahora toca.


Creo haber comentado ya algunas de las novedades del presente documento, que son menos que las que presenta el modelo de informe, aunque algunas hay y no necesariamente favorables para los SEO, pero en general se trata de un documento conservador, que se mantiene en la misma línea que los que le han precedido y que, al igual que aquellos, carece de herramientas para facilitar el trabajo de los SEO.

Mi idea es presentar aquí un docap que facilite el trabajo con el documento, empleando diferentes procedimientos de automatización de su cumplimentación. El resultado queda disponible como enlace al final de esta entrada.

El dictamen de escolarización es, en lo formal, es un formulario basado en tablas, claramente diseñado para ser cumplimentado desde el procesador de texto. dado que es un documento de uso obligado, no da lugar a propuestas de mejora, así que poco hay que decir al respecto, salvo constatar las múltiples posibilidades que presenta en lo que a mejoras se refiere. Y estoy pensando únicamente en las de carácter formal y de uso del documento. Del resto (el contenido y la carga conceptual que conlleva) mejor me mantengo en silencio, por lo que me centraré en explicar el funcionamiento del docap.

El enfoque que desarrollo en este docap es diferente a propuestas anteriores sobre otros modelos documentales similares (ver [aquí] una propuesta anterior), y puede que incluso menos ambiciosa, ya que aquella era una propuesta que implicaba el uso de un docap complejo, que involucraba y relacionaba varios documentos, y esta se limita a un docap simple, basado en un único documento (Writer). No obstante lo que aquí presento supone una mejora significativa en lo que al desarrollo del código se refiere, por lo que no creo que se trate de una simplificación de procedimientos que redunde negativamente en la funcionalidad de uso, más bien al contrario.

Este modelo de docap no permite unificar el proceso de creación de los diferentes documento prescriptivos (como sí sucede en el docap que se cita antes), pero gana en simplicidad de uso y supone una mejora importante del código.

Empezando por la forma de uso, es suficiente con hacer clic en el botón de comando (Crear DE) para que automáticamente se desarrolle la secuencia de pasos que se definen en el código, obteniéndose al final y como resultado, el documento cumplimentado y listo para ser archivado para su posterior manejo según las prescripciones de la Consejería, incluyendo su conversión el formato pdf (proceso que hay que realizar "manualmente" usando las funcionalidades de Writer). Lo que toca hacer al OE responsable de su elaboración es ir introduciendo los datos que se le solicitan mediante funciones InputBox() y MsgBox() (3)

No se contempla cumplimentar el anexo 1 ya que que su elaboración compete al ER (4y no al EOE del sector, por lo que, en la práctica, dicho anexo es tratado como un documento independiente del dictamen, aunque se incluya en él.

Se centra en el proceso de Nuevas Escolarizaciones (5), por lo que determinados campos son obviados, ya que no corresponden precisamente por su especificidad o cuyo contenido está ya predefinido por este mismo proceso. La consecuencia es que el contenido de determinados campos se asigna directamente en el script o no se tiene en cuenta.  

Como cabe esperar, por motivos de confidencialidad, cuando en el código se incluyen datos personales (alumnado, familias, OE), éstos son inventados.

Comento a continuación la estructura de script del docap y su funcionamiento básico.

Consta de 15 script que se distribuyen en 3 módulos:
  • Principal, que contiene el script principal (Carátula)
  • Auxiliares, que contiene las subrutinas y funciones que permiten el desarrollo de los procedimientos requeridos por el script principal
  • Matrices, que contiene las funciones que permiten la elección de los contenidos de los campos de selección (6)
El funcionamiento interno del algoritmo se basa en la llamada a las subrutinas y funciones desde el script principal,  facilitando así el funcionamiento modular del conjunto. En la base de este funcionamiento está el principio de linealidad o sucesión, de modo que el proceso se va desarrollando según el desarrollo del propio documento, tal y como éste se visualiza.

El uso de una matriz general de asignación de contenido (mDatos ()) permite la cumplimentación de los campos mediante un bucle (For) que, a su vez llama a la subrutina de escritura (Posicionamiento). Estos campos se identifican en el documento mediante marcadores, por lo que script y documento quedan relacionados mediante esos marcadores que han sido ubicados en el documento previamente (7)

For i = 0 To 33:
sVar = mDatos(i)
Posicionamiento(sVar,"d",i)
Next
La correspondencia de los numerales de los marcadores y de la matriz facilitan la correspondencia entre ambos y la variable contador (i), garantizando la correcta ubicación del contenido de la matriz en las posiciones que indican los marcadores.

Mediante [este enlace] puedes acceder al docap. Se debe descargar, guardar donde se desee y abrir con LO-Writer activando macros. Se recomienda crear antes manipular el documento y sus script te recomiendo crear una copia del mismo que sirva de copia de seguridad. Así se evita que cualquier alteración del original obligue a realizar una nueva descarga del documento. Es preferible que esa copia de seguridad se haga en formato plantilla y que se trabaje abriendo el documento en esta versión.

NOTAS

(1) En realidad se trata de una serie de tres entradas que se complementan. Aquí la [segunda] y la [tercera].

(2) Se trata de las siguientes indicadas en el apartado Documentos prescriptivos de la sección [Usos]: [campos simples], [campos condicionados], [campos calculados] y [campos de selección]. En la primera de esta serie se habla del docap que se presenta en la actual, dando cumplimiento así a la promesa pendiente.

(3) Me he ahorrado conscientemente (también de las consecuencias negativas de esta decisión) el trabajo de implementar recursos de interface más "vistosos", ya que se trata de una propuesta pensada para que sea  accesible a un orientador interesado en ajustarla a sus propias necesidades. Carece de ambición comercial y no hace concesiones a este enfoque, así que se sacrifica lo "vistoso" (incluso lo amigable) a lo funcional, también en términos de acceso al código y a su posible modificación por el usuario. 

(4) Equipo Regional para la Atención del Alumnado con NEAE. Consejería de Educación del Principado de Asturias.

(5) Proceso cuyo responsable por norma es el equipo de sector y en el que colabora, si así se considera, el ER. El objetivo de este proceso y a la vez programa (para estos SEO) es facilitar la escolarización de los niños y niñas con NEAE (fundamentalmente NEE) en 1º de E. Infantil para el curso siguiente, atendiendo a sus necesidades educativas. La resolución del mismo corresponde a una Comisión de Escolarización. 

(6) Puedes encontrar la explicación de su estructura y funcionamiento en esta entrada ([campos de selección]

(7) Previo a la creación del código se estudia el documento y se determinan las posiciones (campos) que es necesario identificar. Sobre esta base se crea una tabla de tres columnas en las que se enumeran y relacionas los marcadores, los elementos de la matriz (mDatos()) y el contenido. Posteriormente se ubican los marcadores en las posiciones correspondientes, los cuales se enumerar de forma sucesiva mediante un código alfanumérico simple (vg. d0,d1,d2...). Esto permite la posterior correspondencia entre marcadores y elementos de la matriz, de modo sea posible realizar la automatización de la escritura mediante un bucle For, tal y como se explica en el texto.