jueves, 16 de mayo de 2024

OOo Basic. Interface.

Formularios (b). Writer (1)

Analizo ahora el acceso a los controles de uso más frecuente en un formulario desde OOo Basic. Esta entrada complementa, pues, una [entrada anterior] en la que se analizó el esquema general de trabajo con formularios desde un script.




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

Como ya sabemos, todos los controles de formulario deben ser implementados en el documento-soporte (ver [aquí] en los primeros párrafos de la entrada sobre procedimientos de implementación de Formulario), pero además es posible (y generalmente necesario) conformar la apariencia y forma de funcionamiento de cada uno de ello 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 del modo que deseemos.

El control Cuadro de texto posiblemente sea el control más sencillo ya que se comporta funcionalmente como un InputBox(). No obstante presenta características plenas como Control de formulario (por lo que debe ser tratado como tal) y posibilidades de uso diferentes (y mucho más ricas) que las que ofrece InputBox() (3). El modo de acceso a su contenido sigue el procedimiento descrito en la segunda parte de [esta entrada], a la que remito para no repetirme aquí. Me limito ahora a explicar cómo podemos acceder al contenido textual propio de Cuadro de texto.

Dim oTxtNombre As Object
Dim sNombre As String
Dim mDatos(6) As String

oTxtNombre = oForm.getByName("txtAlNombre")
sNombre = oTxtNombre.Text
mDatos(0) = oTxtNombre.Text
  • Definido y caracterizado el funcionamiento de Cuadro de texto desde Propiedades del control, queda identificado por su Nombre (una de las opciones disponibles en Propiedades del control); por ejemplo "txtAlNombre" . Este nombre nos facilita una de las formas de acceso al control (oTxtNombre = oForm.getByName("txtAlNombre"))
  • Previamente deberemos haber creado una variable tipo Object para capturar el objeto control deseado (Dim oTxtNombre As Object), ya que necesitamos esta variable para hacer posible el acceso al control y a su contenido.
  • Tras acceder al control según la sintaxis ya expuesta (oTxtNombre = oForm.getByName("txtAlNombre")), la segunda fase del procedimiento consiste en acceder al contenido, necesariamente de tipo texto, dada la naturaleza de Cuadro de texto. Esto nos obliga a declarar previamente una variable tipo String o una matriz del mismo tipo (Dim sNombre As StringDim mDatos(6) As String en nuestro caso) (4), a la que  asignar el contenido del control.
  • Esta asignación se realiza mediante la siguiente instrucción. En ella oTxtNombre contiene el objeto Cuadro de texto y a través del objeto accedemos a su atributo Text, que es el que contiene a su vez el texto que el usuario ha introducido en Cuadro de texto, cadena alfanumérica que pasa a ser referenciada en la variable sNombre
sNombre = oTxtNombre.Text

El control Cuadro de lista se diferencia del control anterior por sustituir la entrada de texto de escritura libre por una entrada de valores, que es el listado de opciones que se presentan a la elección de 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 opción también permite asociar el control a una tabla, una consulta o a otras opciones.

El acceso al control Cuadro de lista es igual que el acceso a Cuadro de texto, pero no así el acceso al contenido (en  este caso) seleccionado (la entrada del Cuadro de lista por el que opta el usuario). Observa el siguiente segmento del script:

Dim oCurso As Object, oCursoVista As Object
Dim sCurso As String
Dim mDatos(6) As String

oCurso =  oForm.getByName("curso")
oCursoVista = ThisComponent.getCurrentController.getControl( oCurso )
sCurso = oCursoVista.getSelectedItem()
mDatos(2) = oCursoVista.getSelectedItem()
  •  Para acceder al Cuadro de lista necesitamos dos variables Object
    • La primera (oCurso) nos permite acceder al control como tal (oCurso =  oForm.getByName("curso"))
    • y la segunda (oCursoVista) a su listado de opciones (oCursoVista = ThisComponent.getCurrentController.getControl( oCurso ))
  • Posteriormente asignamos la opción seleccionada (método getSelectedItem()) a una variable String, previamente declarada (Dim sCurso As String) haciendo uso de ese método (sCurso = oCursoVista.getSelectedItem()) (5)

El control Botón de opción es en realidad un conjunto (al menos dos) de controles que se vinculan entre sí, ofreciendo al usuario la posibilidad de elegir entre uno de ellos (el resto se descartan), por lo que presenta un comportamiento similar al del Cuadro de lista (en el que el usuario debe optar por una de las opciones que se le presentan), aunque en su apariencia formal son muy diferentes.

También lo son en 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() (6).

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 (Dim oBtn1 As Object, oBtn2 As Object): el primero para capturar la pulsación del botón btn1 (oBtn1 = oFormulario.getByName("btn1")) y el segundo para capturar la pulsación del botón btn2 (oBtn2 = oFormulario.getByName("btn2"))

 


el acceso a los controles casilla botón presenta un grado de dificultad intermedio entre los dos anteriores y más similitud entre sí de la que aparenta. Se diferencian, eso sí, en el modo en que se utilizan en un formulario incrustado en Calc en el que estos controles se asocian a celdas, pero no tanto en caso de acceso directo (cuestión esta aun no tratada).

De hecho en Writer a los datos de casillas y botones se accede del mismo modo mediante OOo Basic, esto es, mediante el valor que adopta la función state(), que permite identificar si el botón o la casilla han sido seleccionados (1) o no (0) (valores booleanos).

Pero el funcionamiento de ambos controles en el funcionamiento dentro del formulario es diferentes: mientras que los botones se presentan claramente asociados y vinculados, las casillas son y tienen un funcionamiento independiente (unas de otras).

Documento
Este documento no tiene más función que la de ejemplificar el funcionamiento de las casillas y botones y de mostrar el modo de acceder a su contenidos mediante script OOo Basic.

NOTAS 

(1) Al igual que la [entrada que la precede], ésta sustituye e incluye el contenido de otras dos publicadas el día 8/07/2023. En ambas se analizaba el funcionamiento de un formulario creado sobre Writer y usado desde un script OOo Basic y el modo de acceso al contenido de sus controles.

(2) 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.

(3El 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.

(4) La doble asignación a variable + matriz es innecesaria, aunque aquí la empleamos por motivos didácticos. En la explicación que sigue a esta nota en el cuerpo de la entrada sólo se recoge una de las dos alternativas de asignación, pero en el script se emplean ambas. El uso de la doble asignación podría estar justificada en algunos casos, pero entonces sería más adecuado que la propia variable se asignara al elemento x de la matriz (sNombre = oTxtNombre.Text -> mDatos(0) sNombre).

(5) Recuerda lo dicho en (4) respecto al tratamiento de la matriz mDatos(). Omito ahora comentar esta parte del script. Al contrario que en Cuadro de texto, en el que el acceso al control requería el uso de la propiedad Text del control (sNombre = oTxtNombre.Text), ahora el acceso a la opción seleccionada por el usuario se hace invocando los métodos .getCurrentController.getControl( oCurso) del objeto Cuadro de lista. Esto supone un procedimiento mucho más complejo que en caso del control Cuadro de texto o el control Campo de fecha, que sigue el mismo procedimiento: 

oFecha = oForm.getByName("fecha")
sFecha = oFecha.Text

(6) También en este caso deberemos tratar el valor devuelto mediante una estructura decisional (condicional If)

OOo Basic. Interface.

Formularios (a). Writer. (1)

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 (2como asociado a a un script.


En esta entrada trataré sobre el uso del formulario sobre un documento Writer, aunque es extensible a su uso en otros servicios (Imperss, por ejemplo); posteriormente se analizará el uso del formulario sobre una hoja de cálculo (Hc) Calc. Los formularios de base de datos (Base) quedan fuera de nuestros objetivos.

La forma más básica de usar un formulario en Writer (3) es como medio para facilitar la entrada de información a un documento. Es una forma más elaborada de presentar documentos que contienen tablas como recursos para al entrada (input) de datos: un ejemplo, las carátulas de los documentos prescriptivos de evaluación (4).

Cierto que a nosotros nos interesa ir más allá del uso de Formulario como funcionalidad (esto es: nos interesa utilizarlo como recurso input en un script), pero no podemos olvidar que el primer paso va a ser necesariamente crear el formulario en y sobre el documento-base; de ahí la importancia que tiene dominar este prerrequisito; algo que no podemos dar por sentado, ya que como funcionalidad no está directamente disponible y en la práctica, en los documentos de trabajo (tanto los prescriptivos como en los que nosotros mismos creamos) predomina el uso de tablas sobre los formularios como medio de recogida y presentación de la información.

Además los medios para crear un formulario no tienen por qué estar disponibles por defecto, así que pueden quedar ocultos al usuario medio, siendo esta una de las causas de su escaso uso. Por ello, lo primero que tenemos que saber es cómo activar las opciones Formulario: Ver|Barra de herramientas|Diseño de formularios (muestra los controles del diseño de formularios) y Ver|Barra de herramientas|Controles de formularios (muestra la barra de herramientas que nos permite acceder a los diferentes campos de que puede constar un formulario). A partir de aquí lo único que debemos hacer es seleccionar el icono Modo diseño... (5)


... para entrar en la capa dibujo del documento y habilitar el acceso a los controles de formulario, seleccionar el icono del control que deseemos utilizar y posicionarlo en el documento.

Una vez creado el formulario, para crear un script que facilite su uso como recurso Input en un script, necesitamos acceder al IDE y, desde éste, trabajar en el script mediante el lenguaje OOo Basic. En esto centraremos el contenido de esta entrada.

Un script que nos permita acceder a un formulario creado en un documento y a sus controles se divide en tres fases sucesivas: 

  • En la primera accederemos al formulario creado en el documento.

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

oDocumento = ThisComponent
oCapaDib = oDocumento.getDrawPage()
oForms = oCapaDib.getForms()
oForm = oForms.getByName("frmActua")

Observa que todas estas variables son de tipo Object, lo que significa que, en esta fase del procedimiento estamos accediendo a los objetos que están o pueden estar en la base del soporte (del documento Writer) según la lógica de su código como programa.

Observa también que, siguiendo esa lógica, el formulario se ubica (es accesible) desde la capa gráfica del documento (DrawPage()), de la cual es uno de sus posibles componentes. Esta capa gráfica no es accesible desde la capa en la que nos situamos con el cursor cuando escribimos. (6)

  • En la segunda fase nos centramos en acceder a los controles del formulario y a su contenido.

Dim oTxtNombre As Object

Dim mDatos(6) As String
Dim i As Integer
 
oTxtNombre = oForm.getByName("txtAlNombre")
mDatos(0) = oTxtNombre.Text

 Observa que este subproceso se desarrolla en dos fases:

    • En la primera fase accedo a los controles, que son también objetos, de ahí que las variables que facilitan este acceso se declaran de tipo Object (v.g. Dim oTxtNombre As Object). El acceso se concreta mediante esta expresión: oTxtNombre = oForm.getByName("txtAlNombre")
    • En la segunda fase accedo al contenido de los controles, que como son de tipo texto, asocio a una matriz String (Dim mDatos(6) As String). La sintaxis de esta instrucción para acceder a un control simple de texto es la siguiente: mDatos(0) = oTxtNombre.Text. (7)
  •  Y finalmente, en la tercera, trabajaremos con ese contenido mediante los medios y procedimientos que mejor se ajusten al objetivo del script. Por ejemplo, y para simplificar, mostrar el contenido de los controles en pantalla mediante MsgBox, haciendo uso de un bucle para recorrer la matriz (8)

For i = 0 To 5
MsgBox mDatos(i)
Next

Documento. Te doy acceso al documento que contiene el formulario y el código desde el enlace siguiente:

Recuerda que debes descargarlo y abrirlo con LibreOffice y acceder al script desde el IDE (Herramientas/Macros/Editar macros)

NOTAS

(1) Esta entrada sustituye e incluye el contenido de otras dos publicadas el día 8/07/2023. En ambas se analizaba el funcionamiento de un formulario creado sobre Writer, empleado como interface Input dentro de un script OOo Basic.

(2) 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.

(3) Y en el resto de los servicios, a excepción de Base, que tiene su propia lógica,  al ser dependiente necesariamente de los campos de la base de datos.

(4) Recuerda que puedes convertir un documento Writer en un pdf, incluso manteniendo la funcionalidad del formulario y sus controles. Esto permite crear formularios en pdf para que el usuario los cumplimente sin necesidad de tener instalado LibreOffice. Esto da mucha más versatilidad al documento de recogida de datos.

(5Este 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.

(6) El comportamiento del formulario en un soporte Calc es mucho más simple, ya que permite que (algunos) de sus controles se asocien directamente con las celdas de la hoja. Esto facilita el trabajo con formularios (mejor dicho, con los controles de formulario) en Calc.

(7) En realidad esta es una simplificación del sistema de acceso a los datos de los controles, tomando como referencia uno de ellos (Cuadro de texto), que es uno de los más simples (similar a un InputBox(), aunque más complejo. Queda para otra entrada la explicación de cómo emplear y acceder al contenido de diferentes controles del formulario.

(8) Esta es una de las opciones posible, no tanto de trabajo como de ejemplificación y constatación del funcionamiento del script. En un uso práctico deberíamos crear un procedimiento de trabajo que incluye el procesamiento de los datos y su uso para resolver un problema, como, por ejemplo, la creación de un texto en el que se analicen los resultados obtenidos en función de la fase de procesamiento. Pero lo que ahora nos interesa es constatar que hemos accedido a los datos del formulario, base para el desarrollo posterior del script.

martes, 14 de mayo de 2024

OOo Basic. Interface

MsgBox (1)

Para la interacción programa-usuario en LibreOffice contamos con diversos recursos; uno de los más sencillos es MsgBox, que en realidad está pensado para mandar mensajes y avisos de distinto tipo, pero que también sirve tanto como recurso de output (2) como de input, en este caso gracias a su uso como función que permite la bifurcación del programa en asociación con estructuras condicionales (If). En este caso se expresa como MsgBox().



Según lo dicho MsgBox cumple doble función Input-Output. Si la empleamos como recurso output muestra algún tipo de información, como en la imagen que antecede; pero si la empleamos como input (función MsgBox()) lo fundamental es que devuelve un valor numérico dependiendo del botón de comando que pulsemos, lo que nos permite capturar este valor y darle un determinado significado mediante el código.

Para la correcta configuración de MsgBox() debemos saber que admite varios parámetros, aunque sólo el primero (el mensaje o prompt) es obligatorio, permitiéndolos opciones de mensaje, título, icono y comandos: (3)

MsgBox (Mensaje As String, Tipo As Integer, Titulo As String)

  • Mensaje es el texto que deseamos mostrar. Puede diferenciarse en varias líneas (Chr(13) genera el salto de línea) y podemos sustituir el texto por una variable de tipo String.
  • Título también es de tipo String y, como su nombre indica, nos sirve para personalizar el título que presentará MsgBox().
  • Tipo es un valor Integer (en realidad una clave o conjunto de claves) que permite identificar el conjunto Icono + Botones (de uno a tres) siguiendo una combinación que se puede presentar como sumatorio o como resultado de la suma: en el primer caso, el primer sumando representa el comando o botón activo (4), el segundo sumando representa el código del comando o comandos (botones) que se muestran y el tercer sumando indica el icono que mostrará MsgBox(). Puede haber un tercer sumando que sirve para indicar cual de los dos o tres botones es el seleccionado por defecto. El cuadro que sigue facilita la comprensión del uso de estos códigos:
Sin iconos
  • 0 - Sólo muestra el botón Aceptar.
  • 1 - Muestra los botones Aceptar y Cancelar.
  • 2 - Muestra los botones Reintentar, Ignorar e Interrumpir.
  • 3 - Muestra los botones Sí, No y Cancelar.
  • 4 - Muestra los botones Sí y No.
  • 5 - Muestra los botones Reintentar y Cancelar.
Iconos

  • 16 - Añadir el icono de Stop
  • 32 - Añadir el icono de Pregunta
  • 48 - Añadir el icono de Exclamación
  • 64 - Añadir el icono de Información

Acceso a botones

  • 128 - El primer botón es el predeterminado. También cuando no se usa 128
  • 256 - El tercer botón es el predeterminado cuando hay tres; si hay dos es el segundo.
  • 512 - El mismo funcionamiento que el código 256

Dado que estos códigos funcionan como números, tanto la expresión suma como su resultado tienen el mismo efecto. Por ejemplo:

Para mostrar un MsgBox con los botones Sí - No (código 4) y el icono Pregunta (código 32) con el botón No seleccionado (código 256) la expresión del tipo puede ser indistintamente:

    • 4 + 32 + 256
    • 292
Interesa también plantearse un manejo diferente de estos parámetros (los tres) de MsgBox, ya que, especialmente el mensaje o texto que mostramos en MsgBox pero no sólo él, es susceptible de ser tratado como variable y ésta sometida a decisión en función del desarrollo del algoritmo. Esto confiere a MsgBox una función mucho más dinámica y potente que la de mero recurso para la emisión de avisos circunstanciales.

Cuando empleamos MsgBox como mensaje, normalmente se presenta directamente, seguido del mensaje (MsgBox "Hola Mundo"), aunque también es posible expresar los parámetros de la función (MsgBox "Hola Mundo", 48, "SALUDO UNIVERSAL"). Pero cuando necesitamos capturar el valor del comando pulsado, necesitamos asignar dicho resultado a una variable (vRpt = MsgBox ("¿Es martes?",4,"DÍA DE LA SEMANA"))

Es el manejo posterior de esta variable la que nos permite utilizar MsgBox() como recurso interactivo para el input, ya que podemos asociarla al código de procesamiento. En este caso, MsgBox() queda subsumido e integrado en la estructura decisional del algoritmo. Muestro a continuación un ejemplo:

Dim iRpt As Single, i As Single

Dim mTratm(2) As String 

 iRpt =MsgBox("¿Es niño?,4,"DATOS DEL ALUMNO")

MsgBox iRpt 

If  iRpt = 6 Then

mTratm() = Array ("niño","alumno","el")

ElseIf  iRpt = 7 Then

 mTratm() = Array ("niña","alumna","la")

End If

For  i = LBound( mTratm() ) To UBound(mTratm())

 mTratm(i)

Next 

 MsgBox mTratm(2) & " " &  mTratm(0) & " es " &  mTratm(1) & "..."

Analizo el script:

  • Las variables iRpt tienen que ser números enteros; la primera por razones obvias (MsgBox() devuelve un valor numérico) y la segunda por su función como contador en el bucle For. Además las categorizo como Single dado que esos números son enteros son pequeño, aunque es frecuente declararlas como Integer.
  • La matriz mTratm() cumple aquí la función de resultado de la bifurcación y podría ser sustituida por un conjunto de variables, no necesariamente de tipo String. Su peculiaridad viene dada por los objetivos que se persigan con el script, que en este caso es definir el tratamiento gramatical en función del género (MsgBox mTratm(2) & " " &  mTratm(0) & " es " &  mTratm(1) & "...")
  • Mediante la expresión  iRpt =MsgBox("¿Es niño?,4,"DATOS DEL ALUMNO"),  basada en la función MsgBox() se asigna a la variable iRpt el valor numérico resultante de la pulsación de los comandos "Sí-No" que se indican como segundo parámetro de la función. Los otros dos son el mensaje y el título de MsgBox() tal como se muestra en pantalla.
  • En la línea siguiente (MsgBox iRpt ) se usa MsgBox con funciones meramente informativas (de control del resultado de la función anterior). Es una línea de código que en la versión final del script se puede eliminar o comentar, una vez comprobado el correcto funcionamiento del script.
  • Sigue una estructura condicional (If... ElseIf...End If) que, en este caso "bifurca" el script en términos de expresiones gramaticales de género, dando contenido (mediante el array) a la matriz  mTratm() (mTratm() = Array ("niño","alumno","el")) en función del valor que devuelve el comando pulsado por el usuario (Sí -> 6, No -> 7)
  • Sigue un bucle For cuya función es (en este caso) también meramente informativa, por lo que es prescindible en la versión final de este script. Mediante este bucle recorremos los elementos de la matriz para comprobar que los valores asignados son correctos.
  • Y finalmente aplicamos el resultado del proceso anterior a la composición de un texto mediante concatenación de String y de los elementos de la matriz mTratm(). El MsgBox que nos muestra en pantalla este texto es un ejemplo de su función output.
Se espera del lector que analice y pruebe este script y sea capaz de idear el suyo propio.

NOTAS

(1) Esta entrada sustituye las creadas con fecha 16 de julio de 2023 sobre MsgBox como recurso de Input y de Output a las que sustituye.

(2) Además de MsgBox, e incluso más simple aun, en OOo Basic también podemos usar la instrucción Print (Print("Texto")), aunque lo cierto es que es una instrucción que se emplea muy poco, salvo como forma de comprobación del funcionamiento del código durante su creación.

(3) Además de los números (ver en el texto de la entrada), también podemos emplear expresiones alfanuméricas como las que se indican en la página de ayuda de LibreOffice, si bien por simplicidad son preferibles la expresión numérica de los parámetros.

(4) Este dato puede estar ausente y el orden puede variar sin que afecte al funcionamiento. Si en lugar de pulsar el comando se usa Intro como respuesta, el valor que devuelve la función será el de comando activo, que, en teoría, se define como sigue:128 - 256 - 512 activan respectivamente los botones 1º, 2º y 3º. En la práctica he observado que 128 y 256 activan el primer botón y 512 el segundo. 

Recursos. Evaluación.

Escala McCarthy (MSCA)

En 2010 elaboré este soporte basado en LO.Calc sobre la escala MSCA. El objetivo de este instrumento era la recopilación de los datos obtenidos en la aplicación de esta escala de uso frecuente en la evaluación del desarrollo psicomotor de los niños de E. Infantil.


Este recurso fue creado originalmente sobre MSO.Excel en el tercer trimestre del curso 2009/2010 y muy posteriormente transformado al formato LO.Calc. Presenta cierta complejidad debido a la complejidad de la prueba, aunque el uso de las funcionalidad Excel/Calc es muy básico: únicamente se hace uso de las posibilidades del soporte presenta para crear y organizar tablas, interrelacionar celdas, automatizar la realización de cálculos y crear gráficos de forma automática.


Comparándolo con el formato Word, el empleo de una Hc supone un avance en funcionalidad, pero se infrautilizan las posibilidades que ofrece este soporte y no aporta nada relevante al formato papel, salvo lo básico (favorecer la digitalización de los expedientes) y obliga a duplicar la escritura de los datos y resultados, ya que este soporte no está pensado para ser utilizado en el momento de la aplicación de la escala.

Documento

sábado, 11 de mayo de 2024

OOo Basic. Datos

Funciones de conversión

Muchas veces necesitamos transformar una variable de un tipo determinado a otro tipo diferentes. OOo Basic no es un lenguaje fuertemente tipado, por lo que este tipo de transformación puede realizarla de forma automática sin que nos demos cuenta, pero es importante conocer cómo realizar estos cambios, ya que no siempre ese automatismo funciona o nos interesa. Para ello contamos con las funciones de conversión.



Si empleamos Option Explicit al inicio de un módulo hacemos que OOo Basic pierda la flexibilidad que tiene a la hora de transformar implícitamente las variables de un tipo a otro, obligándonos a usar las funciones de conversión, pero no hace falta llegar a esos extremos para darnos cuenta del interés que tiene conocer estas funciones. Además su uso es tan sencillo que no representa mayor problema y nos facilita escribir un código inteligible y coherente.

Como su nombre indica, una función de conversión es aquella que nos permite transformar una variable (por ejemplo) String Integer en otra (por ejemplo) Integer. Por ejemplo, si usamos InputBox() como interface para solicitar un dato numérico, por definición, InputBox() nos devuelve un dato aparentemente numérico pero en realidad de tipo String (no tiene otra opción), de modo que si queremos trabajar con ese dato como numérico para asignarlo a un variable que definimos como tal, es cuanto menos conveniente utilizar la función de conversión que corresponda para realizar dicha transformación.

Dim iEdad As Integer

        iEdad = CInt(InputBox("¿Cuántos años tienes?"))) 

Si no realizamos la conversión del resultado del uso de InputBox(), el dato resultante será una cadena alfanumérica, pero no un valor numérico. De no mediar la flexibilidad tipológica de OOo Basic, obtendríamos una respuesta de error o lo que es peor: al intentar operar con dicho valor nos provocaría un fallo en el script.

Otra situación interesante (y frecuente) es cuando solicitamos la introducción de un dato de tipo fecha y lo hacemos sobre una interface que devuelve datos tipo alfanumérico (otra vez InputBox(), pero no sólo). Si usamos la función de conversión (CDate()) convertimos el valor devuelto en una fecha y podemos operar con ella como tal con las funciones disponibles o las que creemos nosotros mismos.

Podemos apreciar, por lo dicho, que las funcione de conversión nos permiten, además, utilizar formas de trabajar con los datos y con el proceso Input de forma mucho más flexible de lo que podríamos hacerlo sin contar con ellas. Esta es una segunda utilidad muy interesante.

Veamos cuáles son las funciones de conversión:

La Wiki de OpenOffice nos ofrece una tabla resumen muy útil en cuya columna FC se recogen las funciones de conversión disponibles en OOo Basic. Se debe entender que cada una de estas funciones convierte un dato al tipo que se expresa en ellas (CDate -> convierte el dato al tipo Fecha). Su uso es así de simple (el resto de las funciones usa la misma lógica y sintaxis):

vFechaNacimiento = CDate(sFechaNac)

Como muestra la tabla precedente, todos los tipos de variables cuentan con su función de conversión, a excepción del tipo Object que carece de función de conversión.

Otra restricción (ésta fácilmente comprensible) es que su aparente simplicidad no supone que podamos convertir cualquier dato en otro, ya que el tipo deseado y el dato presentado deben ser compatibles. Por ejemplo, la cadena alfanumérica (un String"Casa" no se puede convertir a Integer por mucho que apliquemos la función de conversión CInt(), pero la cadena alfanumérica "123" sí.

viernes, 10 de mayo de 2024

OOo Basic. Datos.

 Matriz de matrices

Además de las [matrices multidimensionalestambién podemos trabajar con matrices que, en lugar de datos individuales, trabaje con colecciones de datos o matrices. Las matrices de matrices, que son de las que hablamos ahora, se parecen  a las [matrices unidimensionales], pero son mucho más potentes.


La declaración de una matriz de matrices no difiere de la de una matriz unidimensional (Dim mDatos(2) As Variant) (1), siento únicamente la asignación de contenidos la que permite definirla. Por ejemplo:

Dim mDatos(2) As Variant
mDatos(0) = 1
mDatos(1) = "33012"
mDatos(2) = "Jorge López"
 
... es una matriz unidimensional variant, pero...

Dim mDatos(2) As Variant

mDatos(0) = Array("Perro","Gato","Oso","Tiburón","Burro")
mDatos(1) = Array("Cedro","Pino","Caoba","Fresno")
mDatos(2) = Array(("Cobre","Plata","Manganeso","Azufre","Potasio","Hierro")

 ... es una matriz de matrices, ya que cada uno de sus componentes es, a su vez, una matriz unidimensional (2)

Las matrices de matrices presentan una peculiaridad en cuanto a su manejo, ya que para hacer referencia a un elemento concreto deberemos indicar dos índices: el primero, el de la matriz principal, y el segundo, el de la secundaria. Así, por ejemplo, para acceder al componente "Perro", deberemos hacerlo de este modo:

mDatos (0)(0)

... ya que ocupa la posición 0 (inicial) en la matriz principal y también la posición 0 en la matriz a la que pertenece (3)

Pero esta no es la única forma de acceder a los datos internos de una matriz de matrices. También podemos hacerlo creando una matriz temporal a la que asociamos los elementos de la matriz principal. Veamos un ejemplo.

Dim mDatos(2) As Variant
Dim mTmp As Variant
Dim i As Integer, a As Integer

mDatos(0) = Array("Perro","Gato","Oso","Tiburón","Burro")
mDatos(1) = Array("Cedro","Pino","Caoba","Fresno")
mDatos(2) = Array("Cobre","Plata","Manganeso","Azufre","Potasio","Hierro")


mTmp() = mDatos(0)
For i=LBound(mTmp()) To UBound(mTmp())
MsgBox mTmp(i)
Next

mTmp() = mDatos(1)
For i=LBound(mTmp()) To UBound(mTmp())
MsgBox mTmp(i)
Next

mTmp() = mDatos(2)
For i=LBound(mTmp()) To UBound(mTmp())
MsgBox mTmp(i)
Next

For i = 0 To 2
mTmp = mDatos(i)
MsgBox mTmp(i)
Nex

 

For i = 0 To 2
mTmp = mDatos(i)
For a= LBound(mTmp()) To UBound(mTmp())
MsgBox mTmp(a)
Next
Next

  • El primer procedimiento (que se repite tres veces) resulta de combinar la asignación del elemento de la matriz principal a la variable/matriz auxiliar y el uso del bucle para acceder a cada elemento de la matriz auxiliar.
  • El segundo procedimiento únicamente nos devuelve tres datos: el primero de la primera matriz secundaria, el segundo de la segunda matriz secundaria y el tercero de la tercera matriz secundaria.
  • En tercer procedimiento empleamos una estructura de bucle anidado y dos contadores. El primer bucle recorre la matriz principal y el segundo la matriz auxiliar, lo que equivale a recorres las matrices secundarias que previamente han sido asignadas a la auxiliar (4).



NOTAS

(1) En principio puede entenderse como una matriz unidimensional simple cuyos elementos pueden ser datos de distinto tipo, de ahí declararla de tipo Variant. Por otra parte, una matriz de matrices es de tipo Variant, ya que una matriz no es un dato, sino una colección de datos, lo que obliga a considerarla como Variant. Aun aunque TODOS los elementos de TODAS las matrices elementos de la matriz principal sean de un único tipo.

(2) En este caso, ya que hasta donde yo se nada impide que una matriz incluida como elemento componente de  otra no pueda se, a su vez, multidimensional. Otra cosa es que resulte más o menos sencillo manejar este tipo de matriz, dada su complejidad. Y otra más aun que nos resulte de utilidad para el desarrollo del tipo de script que podemos necesitar.

(3) Por la misma razón decir mDatos(1)(0) es lo mismo que decir (en el ejemplo anterior) "Cedro". Si ambas matrices secundarias se definieran previamente como tales (y no como meros Array), por ejemplo como mAnimal() y mArbol, respectivamente, decir mAnimal(0) sería equivalente a decir mDatos(0)(0), o mArbol(0) lo mismo que mDatos(1)(0)

(4) Resulta interesante observar el diferente comportamiento de los tres procedimiento y nos debe servir para hacer un uso correcto de ellos en función del objetivo. No debemos olvidar que disponemos de dos formas distintas de acceder a los datos de la matriz principal, cada uno con sus posibles ventajas y limitaciones.