sábado, 29 de julio de 2023

Funciones.

Macro, subrutina y función

Para entender en qué consisten las funciones hay que tener en cuenta dos cuestiones: las instrucciones específicas que incorpora todo lenguaje para realizar determinadas tareas y el modo en que programamos los script.



La primera de estas cuestiones nos lleva a pensar en las funciones que incorpora todo lenguaje y que sirven para realizar "funciones" concretas y específicas. Un ejemplo son las funciones de conversión de tipos de variables, como CInt() que sirve para convertir una variable de cualquier tipo (string, por ejemplo) a numérica tipo Integer.

La segunda cuestión nos lleva a plantearnos los modos de programar, cuestión ésta de mayor complejidad conceptual y práctica que la anterior, pero ineludible a partir de cierto nivel de extensión y complejidad del código.

La forma de programar básica puede describirse como lineal: el conjunto de tareas que se definen en el algoritmo se convierten en líneas de código que se van sucediendo una tras otra hasta la conclusión del proceso.

Un ejemplo de ello es la forma de programar en el lenguaje Basic al inicio de la popularización  de los ordenadores. Otra, sin ir muy lejos, la que supone grabar una macro mediante Grabar macro.

Otra forma de plantearse la creación de programas se basa en reutilizar segmentos de código para simplificar el programa y hacerlo más legible y funcional. La forma más sencilla en que se manifiesta esta opción consiste en llamar a un script desde otro script, algo que también podemos hacer con macros. 

Sub EscribirMsgA
Dim sMsg As String
sMsg = "Hola Mundo 1"
MsgBox sMsg,64, "MENSAJE"
End Sub

 

Sub Receptor1
MsgBox "Mensaje desde script",64,"RECEPTOR 1"
Call  EscribirMsgA
End Sub

En este caso el script EscribirMsgA es funcional en si mismo,  pero también podemos reutilizarlo desde un segundo script (Receptor1llamándolo mediante la expresión Call, de la que podemos prescindir ya que se da por supuesta. Y lo dicho: también podemos hacerlo con una macro en sustitución del script EscribirMsgAaunque en este caso para escribir un texto directamente en el documento Writer.

A pesar de las ventajas de esta opción, también  tiene sus limitaciones; y la más importante es quizá, que es necesario modificar (en este ejemplo) el texto del mensaje en el script (o en la macro) subordinado, lo que en programas largos supone mucho trabajo e incrementa la probabilidad de cometer errores. 

Frente a estas opciones, funcionales pero limitadas, tenemos las subrutinas y las funciones. Empezaremos por aclarar en qué se diferencian ambas.

En OOo Basic las funciones se diferencian de las subrutinas claramente: mientras que las funciones devuelven  un valor (un  dato) y las subrutinas hacen algo, así que lo que "devuelven" es eso que hacen.

Veamos cómo crear una subrutina a partir del script anterior:

Sub EscribirMsgB (sMsg As String)
MsgBox sMsg,64, "MENSAJE"
End Sub

 

Sub Receptor2
MsgBox "Mensaje desde script",64,"RECEPTOR 2"
        EscribirMsgB ("Hola Mundo")
End Sub

Vamos a analizar ahora las diferencias entre EscribirMsgA (script) y EscribirMsgB (sMsg As String) (subrutina), aunque en cosa de denominación podrás comprobar que existe cierta confusión: en la documentación se suele emplear indistintamente el término macro, pero yo prefiero diferenciar entre macro, script (o rutina) y subrutina (1).

  • El script auxiliar (el primero) funciona con independencia del script principal (el segundo); la subrutina no.
  • La subrutina incorpora un identificador de variable en el paréntesis que lleva tras el nombre. En el script no existe dicho paréntesis y, en caso de identificarse una variable asimilable a la que declara la subrutina (es el caso de EscribirMsgA) se declara dentro del script y asigna contenido también dentro del script.
  • Mientras que en la llamada al script desde el principal (Receptor1) simplemente se llama al script auxiliar (Call  EscribirMsgA), al ser llamada la subrutina es necesario añadir un paréntesis tras el nombre y un contenido, en este caso un texto  (EscribirMsgB ("Hola Mundo")(2)

También podemos convertir las macros simples (algunas de ellas) en subrutinas, pero no en funciones, ya que las macros siempre hacen algo. Para ello, y en primer lugar, tenemos que diferenciar las que llamamos variables de sistema (que son de tipo objeto) de las que utilicemos para dar contenido concreto a la macro. A estas segundas son a las que daremos el tratamiento de subrutina, ya que las primeras, es posible darlas ese tratamiento, pero también otros, siendo preferible optar por uno más propio del trabajo con macros simples. Lo veremos a continuación en el ejemplo que vamos a desarrollar en base a la macro de escritura de texto.

Sub EscribirMsgC  (sTexto As String)
Dim document   as object
Dim dispatcher as object
document   = ThisComponent.CurrentController.Frame
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")
Dim args2(0) as new com.sun.star.beans.PropertyValue
args2(0).Name = "Text"
args2(0).Value = sTexto
dispatcher.executeDispatch(document, ".uno:InsertText", "", 0, args2())
End Sub

 

Sub Receptor3
MsgBox "Mensaje desde macro",64,"RECEPTOR 3"
EscribirMsgC ("Hola Mundo")
End Sub
  • Puedes observar que he formulado la macro del mismo modo que la subrutina. Gracias a ello, de hecho, he convertido la macro en una subrutina, aunque sería más correcto decir que esta formulación está a medio camino entre macro y subrutina, ya que mantiene componentes y formas propias de las macros, incorporando otras propias de la subrutinas. También sus "limitaciones": no funciona autónomamente, debiendo ser llamada desde un script "principal". 
  • El script "receptor" trata la macro como subrutina, tal y como podemos observar en la forma en que la llama (EscribirMsgC ("Hola Mundo"))

Frente a las subrutinas, en OOo Basic las funciones se diferencian claramente ya en su formulación: al denominarlas (apertura y cierre) se debe usar el identificador Function:

Function AreaCuadrado( iLado As Integer) As Double
    Dim dArea as Double
    AreaCuadrado = iLado * iLado
End Function

Esto es:
    • La función se declara con la expresión Function y finaliza con  End Function.
    • La función no funciona independientemente, necesita ser "llamada" desde un script principal.
    • Además del paréntesis donde se declaran las variables, también finaliza con una tipificación (As Double) que permite entender qué tipo de valor devuelve (numérico Double, en este caso) así como que la propia función es una variable, como de hecho lo es (o como tal se comporta), ya que devuelve un valor (el que contiene como variable)
    • El resultado del procesamiento interno de la función se asigna a la misma función a modo de variable (volvemos al punto anterior): AreaCuadrado = iLado * iLado. Otra formulación no provoca que la "función" dé error, pero tampoco devuelve nada.
Veamos cómo se formula el que llamamos script principal:

Sub Cuadrado
Dim sResultado As String
Dim iLong As Integer
Dim dArea
iLong = InputBox ("Dime el lado del cuadrado")
dArea = AreaCuadrado(iLong)
sResultado = "El cuadrado de lado " & iLong & " tiene un área de " & dArea
MsgBox (sResultado,64,"AREA DEL CUADRADO")
End sub

Puedes observar que la "llamada" a la función se diferencia de la llamada a la subrutina en que en la primera utilizamos la asignación a una variable, lo cual no hacemos en la llamada a subrutina puesto que la función es un valor (se comporta como una variable que tiene asignado un dato o valor), por lo que debe ser recogido por (y asignado a) una variable. Después podrá ser tratado como dato, tal y como sucede en este ejemplo en su concatenación en la variable string sResultado (3)

NOTAS

(1) Las funciones se diferencian claramente, por lo que no existen estos problemas terminológicos.
(2) Podríamos sustituir el texto por una variable, pero en este ejemplo he optado por la formulación más sencilla. En ese caso, dicha variable es diferente de la que se declara en la subrutina, aunque termina cumpliendo la misma función que aquella. Esta equivalencia viene facilitada por la funcionalidad compartida de ambas: complementan la forma en que se escribe la subrutina.
(3) En la que contradigo lo que he considerado conveniente en otra entrada: no convierto las variables numéricas en string, como sería recomendable, por lo que una buena formulación de esta instrucción sería la siguiente: sResultado = "El cuadrado de lado " & CStr(iLong) & " tiene un área de " & CStr(dArea)

domingo, 23 de julio de 2023

OOo Basic. Datos

Colecciones de datos. Matrices

Cuando los datos individuales se presentan asociados por algún criterio y son relativamente numerosos, parece conveniente agruparlos para facilitar su manejo. Esta función la cumplen las matrices.


Precisamente la mayor utilidad de las matrices es ahorrar el trabajo de escribir largas series de variables, facilitando además procedimientos de acceso a su contenido. Las matrices constituyen sistemas estructurados de almacenamiento.

La declaración de una matriz no es demasiado diferente de la declaración de una variable, salvo por añadir un paréntesis tras el nombre que, además de identificarla como matriz, indica el número de elementos con que se declara:

Dim mAlumnado(5) As String

Bueno, más que el número, el límite superior de los elementos que la conforman, ya que, salvo indicación específica, las matrices se inician en OOo Basic con el índice 0, con lo que una matriz(4) contiene las posiciones identificadas por los índices 0 - 1 - 2 - 3 - 4 (total, 5 elementos)

Para dotar de contenido a una matriz disponemos de varias opciones:

  • Introducirlo directamente, empleando el índice como referencia

mAlumando(0) = "Juana López Suárez"
  • Hacer que sean el resultado del procesamiento de datos preexistentes
mAlumnado(0) = sNombre & " " & sApellidos
  • Introducirlos externamente o capturarlos de una fuente de datos mediante algún procedimiento de input
mAlumnado(0) = InputBox ("Nombre y apellidos del alumno :")

Pero también podemos introducirlos directamente como una lista mediante la [función Array()], separando cada elemento con una coma.

mAlumnado = Array("Juana López Suárez", "Antonio Martínez Núñez", "Casimiro Rodríguez Fernandez", "Ana Martínez Sanz", "Susana García Méndez")

Esta función es de gran utilidad cuando deseamos introducir directamente los datos de la matriz, ya que evita tener que identificar cada elemento, uno a uno. Otra ventaja de la función Array() es que nos permite introducir un número de elementos diferente del establecido en la declaración de la matriz, lo que la redimensiona de forma automática.

En relación con lo anterior, hasta el momento hemos hablado de matrices de dimensiones conocidas, lo que supone de sabemos dónde empiezan (mAlumnado(0)) y dónde terminan (mAlumnado(4)); pero es posible que, en script complejos si usamos la función Array(), o cuando capturamos datos externos, no sepamos a priori ni dónde empieza ni donde termina una matriz, especialmente dónde termina. Para estas situaciones son de gran utilidad las [funciones LBound() y UBound()]:

  • LBound(mAlumnado()) nos devuelve el índice con el que inicia la matriz

  • UBound(mAlumnado()) nos devuelve su índice de finalización.

Dado que la variación del tamaño de una matriz es una maniobra relativamente frecuente, OOo Basic dispone de dos funciones que nos permiten realizar esta tarea de forma sencilla: mediante las [instrucciones ReDim y Preserve]. La primera redimensiona la matriz y la segunda permite mantener el contenido previo.

Sobre todas estas cuestiones hablaremos en posteriores entradas, aunque puedes adelantarte accediendo a su contenido mediante los enlaces que incluyo en la actual, que sirve introducción.

sábado, 22 de julio de 2023

OOo Basic. Estructuras

Bucle Do Loop

Mientras que el desarrollo de la iteración For se basa en la ejecución de un ciclo definido por los límites de una variable-contador, Do...Loop se basa en el cumplimiento (o no) de una determinada condición. 



Precisamente
 la diferencia entre ambos (For y Do) radica en que mientras que la primera implica necesariamente la ejecución de al menos una iteración, en Do
 puede darse el caso de que no se ejecute en ningún momento, dado que es posible que la condición necesaria no se cumpla nunca.


La sintaxis de Do es notablemente más compleja que For, como tendremos ocasión de comprobar en esta entrada por comparación con [la anterior], admitiendo Do dos variaciones básicas que, a su vez, presentan dos formas diferentes de plantear la condición de persistencia o finalización del bucle mediante dos instrucciones diferentes: While y Until. Veamos cada una de ellas (fuente de los gráficos libreoffice.org).

La primera de estas dos opciones es la que está representada en el gráfico siguiente: podemos advertir que las condiciones se plantean al inicio de la estructura, ubicándose las instrucciones While y Until asociadas a Do.


Este posicionamiento de la condición permite que no se ejecute el bucle ninguna vez si la condición que se establece no es verdadera (Do While)...

sub BucleA1

Dim iCondicion As Integer

iCondicion = 0

Do While iCondicion > 5

MsgBox iCondicion

iCondicion = iCondicion +1

Loop

End Sub

... como en este caso. Para que se ejecutar el bucle deberíamos cambiar el signo de la condición ( Do While iCondicion < 5) ...

... o mientras no lo sea (Do Until)...

sub BucleA2

Dim iCondicion As Integer

iCondicion = 0

Do Until iCondicion < 5

MsgBox iCondicion

iCondicion = iCondicion +1

Loop

End Sub

... no se ejecuta el bucle y para que se ejecute deberemos cambiar la condición en sentido contrario (Do Until iCondicion > 5) (1).

Contrariamente a la anterior, una segunda opción sitúa la condición asociada a Loop, motivo por el que While o Until se posicionan tomando a esta instrucción como referencia. El esquema siguiente representa esta segunda opción.


La consecuencia de este posicionamiento es que el bucle se ejecutará como mínimo al menos una vez, hasta que se comprueba que se cumple o no se cumple la condición que se establece. Por ejemplo...

sub BucleB1

Dim iCondicion As Integer

iCondicion = 0

Do

MsgBox iCondicion

iCondicion = iCondicion +1

Loop While iCondicion > 5

End Sub

... en este caso (Loop While) el bucle se ejecuta una vez MsgBox iCondicion -> 0, ya que la condición se comprueba asociada a la instrucción Loop. Para que se ejecute hasta que deja de cumplirse la condición debemos cambiar el signo de la comparación (Loop While iCondicion < 5): ahora se ejecutará hasta que iCondicion valga 5 (iCondicion=5), momento en que dejará de cumplirse.

Otra posibilidad es la que representa el siguiente script:

sub BucleB2

Dim iCondicion As Integer

iCondicion = 0

Do

MsgBox iCondicion

iCondicion = iCondicion +1

Loop  Until iCondicion < 5

End Sub

En él también se ejecuta el bucle una vez hasta que se comprueba que se cumple la condición para que no se ejecute, momento en el que finaliza en cumplimiento de la instrucción dada (Loop  Until iCondicion < 5), siendo necesario cambiar dicha condición (Loop  Until iCondicion > 5) para que persista ejecutándose hasta que se cumpla la condición se finalización que se establece.  

Las función específica y diferenciada de While y Until también resulta de interés, ya que optar por una o por otra implica priorizar el cumplimiento de la condición para que se ejecute el bucle (While), o establecer la condición que impida su cumplimiento (Until)

Como podemos observar, mientras que asociar la condición a Do vs. Loop modifica el funcionamiento del bucle...

  • Do (While|Until) Condición   -> Puede no ejecutarse nunca el bucle
  • Loo (While|Until) Condición   -> El bucle se ejecutará al menos en una ocasión.
... el uso de While vs Until invierte el sentido del cumplimiento de la condición:

  • While   -> Repite el bucle hasta que la condición sea falsa (deje de cumplirse)
  • Until    -> Repite el bucle mientras la condición es verdadera y finaliza cuando pasa a ser falsa.
Parece claro que el bucle Do presenta más dificultades de uso que el bucle For, por lo que éste es preferible siempre que lo que se pretenda ejecutar permita ser planteado de forma alternativa con una o con otra estructura; pero no es menos cierto que Do...Loop puede ser oportuno en determinadas circunstancias, como cuando queremos asegurar el cumplimiento de una condición y una forma determinada de funcionamiento del bucle, como en el uso de una clave de acceso por motivos de seguridad.

En cualquier caso es necesario tener mucho cuidado con cómo se planea el bucle ya que de hacerlo incorrectamente podemos generar un error de funcionamiento que derive en el bloqueo del programa. Y este peligro es mayor cuando usamos los bucles Do...Loop.

NOTA

(1) Queda claro en los ejemplos anteriores que de la inversión de la ejecución o no del bucle son responsables las instrucciones While vs. Until. De ellas hablaremos más abajo.

viernes, 21 de julio de 2023

OOo Basic. Estructuras

Bucle For Next

Junto con la bifurcación, la iteración constituye el segundo proceso básico de todo algoritmo. En resumen consiste en la repetición de un mismo procedimiento n-veces.



En esencia, un bucle consiste en la repetición de un procedimiento (un conjunto o bloque de sentencias) mientras se cumple una condición, y en su finalización una vez que se deja de cumplir dicha condición. 

El segundo tipo de bucle invierte el procedimiento: se repite la sentencia o el bloque de sentencias siempre que no se cumple la condiciones "x" y dejan de ejecutarse en el momento en que se cumplen.

En OOo Basic utilizamos dos estructuras para trabajar con bucles: For...Next y Do...Loop. En esta entrada trataremos el primero y habrá una segunda entrada para explicar el segundo.


La sintaxis de For...Next es la siguiente (lo que se sitúa entre corchetes es opcional):

For Variable = Inicio To (Variable) Fin [Step Salto]

 Bloque de código

[Exit For]

Next [Variable] 

Como puedes ver se utiliza una variable de control (normalmente identificada como contador por su función) que marca el inicio y el fin del bucle (Variable = Inicio To Fin) y también podemos indicar un salto ( o no, ya que este valor es opcional) que será útil si deseamos que la evolución del recorrido valor Inicio - valor Fin(nal) no sea lineal (+1). 

Una vez que se alcanza el valor Fin, entra en funcionamiento Next, dando por finalizado el ciclo. Mientras tanto (hasta ese momento) se ejecuta el bloque de código que se estableciera entre For y Next.

Al igual que Sept nos permite alterar el desarrollo de la secuencia, Exit For nos permite salir anticipadamente del bucle siempre que se cumpla una condición, lo que remite al uso de estructuras de bifurcación, dando lugar a estructuras complejas y mixtas.

Finalmente, el uso opcional de la identificación de variable tras Next (la misma que utilizamos en For como contador) es una buena práctica cuando se anidan dos bucles y cada uno tiene (obviamente) su propio contador: facilita delimitar ambos bucles, pero carece de valor cuando sólo desarrollamos un único bucle.

Ahora vamos a ejemplificar a continuación el uso simple de For...Next, que es la forma en que se utiliza esta estructura con mayor frecuencia. Para ello vamos a generar una tabla de multiplicar, ejemplo típico de este tipo de estructuras.

Sub TablaMultiplicar

Dim iNum As Integer, i As Integer

iNum = 5

For i = 0 To 10

MsgBox (iNum & " x " & i & " = " & iNum*i,64,"TABLA DE MULTIPLICAR DEL " & iNum)

Next

End Sub

Puedes mejorar este sencillo y poco atractivo script haciéndolo interactivo; para ello el valor iNum se establecerá mediante InputBox. También puedes transformarlo en un pequeño "juego" haciendo que sea el alumno quien deba indicar la solución, aunque en este caso te costará un poco más de trabajo, tendrás que crear una variable para contener el valor de la respuesta y el bloque de código será más complejo. En cualquier caso, lo importante y nuclear de qué es y cómo se construye un ciclo For...Next es lo expuesto en el ejemplo que tienes arriba expresado; el resto son "variaciones sobre el mismo tema".

lunes, 17 de julio de 2023

OOo Basic. Interface

InputBox

Aunque MsgBox() puede funcionar también como función como recurso para el input ([ver entrada]), es la función InputBox() el recurso especialmente pensado para este objetivo, definiéndose necesariamente como función, por lo que siempre se asocia a una variable, en este caso y en principio de tipo String.



InputBox permite al usuario interactuar con el script, aportando los datos que necesarios para (por ejemplo) personalizar el contenido del documento y la información necesaria para el correcto funcionamiento del script. Constituye, por ello, una forma sencilla de GUI en sentido estricto. Una interface sencilla y limitada, pero una forma básica de interface muy funcional.


Es además monótona ya que no presenta la variedad de opciones que tienen los controles de un formulario o de un cuadro de diálogo, pero lo compensa con la facilidad con que se implementa.

Lo de limitado es consecuencia de que todas las entradas son originariamente cadenas de caracteres (String) por lo que, en principio se debe asociar a una variable de tipo String. Pero dado que es posible realizar conversiones del tipo de variable mediante [las funciones que ya conocemos], podemos aplicar estas funciones previamente a InputBox()  para asociarlo a una variable no String.

La forma básica en la que se presenta InputBox()...

vNombre = InputBox("¿Cómo te llamas?")

... pasaría a ser para el caso de la edad (valor numérico)...

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

... para Dim vNombre As String y Dim vEdad As Integer.

Recuerda que las funciones de conversión en OOo Basic son las siguientes:

  • CStr() -> Conversión a string
  • CInt() -> Conversión a Integer
  • CVar() -> Conversión a Variant
  • CBool() -> Conversión a Boolean
La sintaxis completa de InputBox() es la siguiente...

InputBox (Prompt As String[, Title As String[, Default As String[, xpostwips As Integer, ypostwips As Integer]]]) As String

... aunque su uso más frecuente es más sencillo, omitiendo los parámetros de posicionamiento en pantalla, por ejemplo (1)

sNombre = InputBox("Dime tu nombre","NOMBRE DE USUARIO","Casimiro",6000,5000)

Primero asignamos a la variable sNombre (String) la respuesta dada (o confirmada) por el usuario. La sintaxis del InputBox() se describe como sigue:

  • Primer parámetro (Prompt) -> "Dime tu nombre", permite especificar la información o dato que se solicita al usuario.
  • Segundo parámetro (Title) -> "NOMBRE DE USUARIO", establece el título del InputBox().
  • A partir de aquí, el resto de los parámetros son opcionales
  • Tercer parámetro (Default) -> "Casimiro", establece una respuesta por defecto. Si se establece este parámetro opcional y el usuario no lo modifica, se considera que lo confirma. Este parámetro se usa para facilitar la entrada de datos cuando existe una respuesta predominante, pero también puede servir para ofrecer varias respuestas posibles y que sea el usuario quien elimine las que no corresponda.
  • Cuarto parámetro (xpostwips) -> 6000, posiciona el InputBox en el valor X 6000 de la pantalla (en pilxes)
  •  Quinto parámetro (ypostwips) -> 5000, posiciona el InputBox en el valor Y 5000 de la pantalla (en pilxes)

InputBox dispone de dos comandos (botones) invariables, Aceptar y Cancelar, el primero de ello seleccionado por defecto. Aceptar pasa el valor a la variable y Cancelar pasa una cadena vacía. En caso de pulsar Intro, el valor por defecto prevalece, por lo que equivale a pulsar Aceptar)(2).

sNombre = InputBox("Dime tu nombre","NOMBRE DE USUARIO","Casimiro",1200,1000)

print(sNombre) -> Devuelve Casimiro

Si lo que deseamos solicitar es un valor numérico (un Integer, por ejemplo), debemos utilizar la función de conversión CInt() aplicada bien a la variable string a la que asignamos el valor resultante de InputBox(), bien a la propia función, ya de que otro modo no se podrá operar con ese valor como numérico al ser éste se tipo String según la definición de InputBox() (InputBox() As String) (3)

Por si te interesa comprobar el funcionamiento de los script usados en esta entrada, en el IDE asociado a este documento tienes el código.

NOTAS

(1) Aunque lo más frecuente es omitir estos parámetros, puede ser interesante tenerlos en cuenta cuando ese posicionamiento sea de interés para el docap. Su principal inconveniente es que ese posicionamiento depende de la resolución del monitor y su tamaño, lo que afecta a la universalidad del código. Posiblemente esta sea la causa de su ausencia en la sintaxis de la función.

(2) Este comportamiento tiene su lógica (es el botón seleccionado por defecto) y sus ventajas: especialmente cuanto tenemos unos cuantos InputBox en el script, se agradece que la confirmación de los datos no dependa necesariamente de pulsar Aceptar; incluso ahorra unos cuanto posibles errores en la entrada de datos.

(3) En realidad el uso de la función de conversión CInt() sólo será imprescindible cuando insistimos en el tratamiento como String de las variables asociadas a InputBox(); en otro caso se realiza la conversión de forma implícita (y automática). No obstante, por claridad de escritura del algoritmo es conveniente respetar el procedimiento de conversión de tipología. Eso obliga a ser claros en lo que buscamos y evita posibles errores de funcionamiento del script. Este principio de actuación es válido para cualquier conversión de tipología de variables.

sábado, 15 de julio de 2023

OOo Basic. Script

Macros. Programación modular

Además de utilizar las macros como resultado de la ejecución de Grabar macro también podemos utilizarlas como elementos discretos a modo de subrutinas. Este enfoque se encuentra a medio camino entre la creación de macros y la escritura de script o programación. Ambos procedimientos pueden ser, además, complementarios. En todo caso remite a [lo que expuse] sobre la programación lineal o imperativa y la programación modular.



Es importante remarcar esa idea de complementariedad, ya que en informática (también) las cuestiones pueden se resolver de diferentes maneras (aunque unas pueden ser mejores que otras), así que lo que no sepamos resolver mediante un script, podemos abordarlo mediante una macro.

Pues bien, si en la [entrada anterior] aprendimos a identificar el contenido de una macro secuencial y a diferenciar diferentes funciones, en esta entrada vamos a profundizar en el modo de trabajo que podemos llamar programación modular que podemos caracterizar por el uso de secuencias de acciones (macros unitarias o de función única) combinadas. 

Este modo de trabajo admite la combinación entre macros unitarias y script, combinación que permite desarrollar programas de cierta complejidad. Algunos ejemplos de ello podemos verlos en [aquí]

Para el correcto desarrollo de un docap basado en este tipo de macros es necesario posicionar correctamente las variables básicas de toda macro, así como crear una macro específica en la que dichas variables se asocien a sus contenidos. Esta macro deberá ser llamada desde las macros individuales, permitiendo así su reutilización, con el consiguiente ahorro de tiempo.

A parte de esto, es importante crear colecciones de macros individuales, necesariamente asociadas al servicio-soporte, las cuales pueden ser aplicadas modularmente cuando sea necesario.

Aunque puede considerarse que es este un modo un tanto rudimentario de "programar", podemos decir que es similar al enfoque funcional y que algunos programas de cierta complejidad (FileMaker, por ejemplo) disponen de recursos de "programación" que, en síntesis, no son otra cosa que una colección amplia de funcionalidades, algo similar en filosofía a lo que aquí se plantea.


lunes, 10 de julio de 2023

OOo Basic. Script

 Trabajar con macros

Ya hemos aprendido a crear una macro sencilla y es posible que te preguntes si el resultado merece el esfuerzo. En principio te diría que en macros como la creada en la entrada anterior, la respuesta dependerá de la frecuencia con la que la usemos: a menor frecuencia, menos "rentabilidad". Pero es que con una macro podemos hacer muchas más cosas... siempre que estemos dispuestos a seguir aprendiendo.




Si recordamos, la secuencia de acciones que desarrollamos para crear la macro anterior fue la siguiente:

    • Nos situamos al inicio del documento
    • Seleccionamos tipo de letra
    • Seleccionamos tamaño de letra
    • Seleccionamos negrita
    • Seleccionamos color
    • Seleccionamos centrado
    • Escribimos una frase
    • Bajamos el cursor
    • Escribimos una segunda frase
    • Bajamos el cursor
    • Nos posicionamos al inicio de la línea
Además recordarás que cometí algunos errores y que los corregí sobre la marcha, de modo que en el resultado final no se aprecian, pero ahí están.

En efecto, todas y cada una de estas acciones han quedado grabada en nuestra macro, incluyendo los errores y su corrección, y ahora están a nuestra disposición para que las reutilicemos. 

Para ello debemos plateamos el uso de las macros desde una perspectiva que no es ni se limita a la que empleamos en la construcción de nuestra primera macro y que se acerca más a la programación.

Desarrollar esta segunda perspectiva pasa por enfrentarnos al código generado por la macro, identificar y eliminar los errores cometidos y diferenciar cada paso de la secuencia que desarrollamos para hacer de cada uno de ellos una herramienta reutilizable.

En [este enlace puedes acceder al documentoen el que se creó la macro.

OOo Basic. Script

 ¿Qué es una macro?

Las macros son tan antiguas como los procesadores de texto, pero han ido evolucionando en funcionalidad al igual que éstos, aunque arrastrando la mala fama que genera ser susceptibles a usos perniciosos.




Originariamente  una macro (macroinstrucción es su nombre completo) no era otra cosa que atajo de teclado para facilitar el trabajo, permitiendo la ejecución de un conjunto de acciones mediante la pulsación de una combinación de teclas. Hoy en día macro y script tiende a confundirse, aunque opino que son dos cosas radicalmente diferentes, tan diferentes como es su proceso de creación: la macro mediante la activación de una funcionalidad llamada Grabar macro y el script mediante la generación de código escrito en un lenguaje de programación desde un programa especial denominado IDE.

A pesar de esta diferencias y todo lo que derivan de ellas, es común en los soportes que admiten macros (servicios de suites ofimáticas) se emplee el concepto macro abarcando ambas realidades.

En principio, y en lo que a esta entrada se refiere, vamos a denominar macro al código que deriva de la aplicación de la grabadora de macros. El hecho de que estemos tratando este tema desde Writer no implica que no sea posible crear macros (según la definición anterior) en otros soportes (por ejemplo Calc), aunque es en los procesadores de texto donde, posiblemente, más utilidad tenga trabajar con macros  por la variedad de posibilidades que éstas tienen en el trabajo con documentos de texto.

Para trabajar con macros es necesario que conozcas unas cuantas cosas que mejor que yo te puede explicar la [documentación oficial de LibreOffice], así que lo dejo en sus manos. Es un documento muy recomendable, aunque encontrarás en él la (para mi) confusión que antes te apunté entre macro y script.

Además puede que te encuentres con que LibreOffice se resiste a dejarte acceder a las macros. Esto es debido al sistema de control de seguridad que tiene activado y a la consideración de las macros como elementos potencialmente peligrosos. Pero como aquí estamos hablando de macros de confianza, [este documento] te permitirá actuar en consecuencia (y en conciencia). El resto queda en tus manos.

Una vez que ya hayas superado las dos fases anteriores, lo mejor que podemos hacer en poner en práctica eso de que la mejor forma de aprender es haciendo, planteamiento que, en términos generales, es más que dudoso, pero que en este caso se acerca bastante a la verdad: aprendamos a trabajar con macros creando una. El [vídeo] que sigue te muestra cómo crear una macro simple.


domingo, 9 de julio de 2023

Documentos. Becas

 Informe para solicitud de beca NEAE 

Una de las tareas que competen al SEO, y concretamente al OE es colaborar en el proceso de solicitud de beca NEAE. La documentación oficial contiene un breve formulario que facilita el cumplimiento de esta responsabilidad, pero  normalmente es necesario complementarlo emitiendo un informe que justifique la solicitud.



No voy a entrar en cuestiones que inciden en la pertinencia de las motivaciones que considero cuanto menos equívoca, así que me limitaré a facilitar un recurso que creo puede ser útil para cumplir esta función. Se trata de un docap construido sobre un documento Writer, como corresponde, basado en el uso de macros revisadas y adaptadas al modelo secuencial estructurado.

Tampoco voy a dar ahora una explicación detallada sobre el funcionamiento de este docap, ya que es preferible hacerlo mediante un vídeo que extenderme aquí innecesariamente. Únicamente unas sencillas aclaraciones:
  • Se trata de un documento Writer sin ninguna referencia al docap, así que es necesario acceder desde el menú Herramientas/Macros/Ejecutar macro/InfoBeca2.odt/Standard/ModEscritura
  • Hacer clic doble en el script Documento o seleccionarlo y hacer clic en Ejecutar
  • Cumplimentar los distintos cuadros de diálogo a los que se accede desde el menú lateral
  • Y finalizar con clic en el comando Guardar.
Automáticamente se escribe el documento (informe-base, si lo prefieres) y posteriormente puedes realizar las modificaciones que consideres. 

Por último sólo te queda guardar el archivo con un nombre representativo de contenido. Yo recomiendo:

  NombreAlumno+InicialesAmbosApellidos+FechaInversa+GuionBajo+InfoBecaNEAE+CXXYY (para curso)

Aprovecho para decirte que cualquier explicación en la que estés interesada sobre cómo funciona este docap puedes encontrarla accediendo al IDE e investigando en la composición del directorios Standard (library) de este documento., subdividida en cuatro módulos y un cuadro de diálogo. 

A continuación tienes referencia de la normativa que sirvió de base para la anterior convocatoria de becas NEAE. Espero que, al menos en parte, te sigua siendo útil, pero ya sabes que estas cosas cambian con frecuencia y hay que estar al tanto...
  • Real Decreto 1721/2007, de 21 de diciembre, por el que se establece el régimen de las becas y ayudas al estudio personalizadas. Ministerio de Educación y Ciencia - «BOE» núm. 15, de 17 de enero de 2008.

  • Real Decreto 476/2013, de 21 de junio, por el que se regulan las condiciones de cualificación y formación que deben poseer los maestros de los centros privados de Educación Infantil y de Educación Primaria. Ministerio de Educación, Cultura y Deporte - «BOE» núm. 167, de 13 de julio de 2013.

  • Resolución de 14 de febrero de 2019, de la Consejería de Educación y Cultura, por la que se convocan procedimientos selectivos para el ingreso en el cuerpo de Maestros al que se refiere la Ley Orgánica 2/2006, de 3 de mayo, de Educación, y para la adquisición de nuevas especialidades por el personal funcionario de este cuerpo. Consejería de Educación y Cultura. BOPA de 18/II/2019

  • Real Decreto 471/2021, de 29 de junio, por el que se establecen los umbrales de renta y patrimonio familiar y las cuantías de las becas y ayudas al estudio para el curso 2021-2022, y se modifica parcialmente el Real Decreto 1721/2007, de 21 de diciembre, por el que se establece el régimen de las becas y ayudas al estudio personalizadas. Ministerio de Educación y Formación Profesional. BOE de 30 de junio de 2021.

  • Resolución de la Secretaría de Estado de Educación, por la que se convocan ayudas para alumnos con necesidad específica de apoyo educativo para el curso académico 2021-2022, de 28/07/2021.

  • Extracto de la Resolución de 28 de julio de 2021, de la Secretaría de Estado de Educación, por la que se convocan ayudas para alumnos con necesidad específica de apoyo educativo para el curso académico2021-2022. Ministerio de Educación y Formación Profesional. BOE de 2 de agosto de 2021.


DocumentoInfoBecaNEAE