viernes, 19 de julio de 2024

Evaluación. Pruebas.

Memoria. Escala RIAS. Test de memoria no verbal (MnV).

Entre los recursos de evaluación de la inteligencia y los procesos cognitivos se encuentra la Escala de Inteligencia de Reynolds (1), y dentro de ella disponemos de dos pruebas para la evaluación de la memoria. En esta entrada hablaré del test de memoria no verbal (RIAS-MnV).

Lo que sigue no pretende sustituir la información disponible en la red, incluyendo el [informe] que elaboró en su momento el Consejo General de Colegios Oficiales de Psicólogos, cuya lectura te recomiendo para una mejor comprensión de las características de RIAS. Evidentemente, también es muy recomendable la lectura de su manual técnico ([aquí un extracto], aunque si tienes oportunidad de acceder al manual completo, mucho mejor). 

En esta entrada mi objetivo no es explicar el uso estándar del test de memoria no verbal, ya que para eso ya está toda la información que proporcionan las fuentes antes citadas y, mejor aun, los materiales originales del test que comercializa la editorial [TEA ediciones]

Lo que yo pretendo es, por decirlo de algún modo, investigar sobre cuestiones que son de interés para un uso "reformulado" de este instrumento de evaluación. Pero para ello es necesario analizar el propio test.

El test RIAS-MnV consta de 44 ítem, aunque la puntuación máxima (PD) que se puede obtener es de 88 pts (más abajo veremos el motivo). Como el resto de los test RIAS, se plantean puntos de inicio en función de la edad del sujeto, así como criterios de retorno y de finalización. Por muy necesario que sean todos ellos, no deja de ser un inconveniente para el manejo funcional de la prueba. Personalmente considero que, aunque aunque es prescriptivo seguir el procedimiento establecido (de ello de depende la validez de los resultados) caben otras opciones complementarias (no sustitutivas) de utilizar la prueba. Estas opciones, que son varias, deberán ajustarse y estar justificadas por los objetivos que nos planteemos en la evaluación (2).

Teóricamente podríamos aplicar RIAS-MnV a partir de los tres años, pero personalmente lo considero poco adecuado para estas edades y, salvo excepciones, no soy partidario de utilizarlo antes de los seis (ítem de inicio 13). No obstante, sí es interesante el análisis de los resultados esperados para todas las edades, incluidos los tramos inferiores.

Cada estímulo se presenta al alumno durante 5", tiempo en principio suficiente para los ítem más sencillos, pero es dudoso que lo sea para los más complejos o para alumnos con algún tipo de dificultad atencional y/o de velocidad de procesamiento. Esta duración (invariable) del tiempo de exposición del estímulo puede ser (3) la causa del fracaso conforme se avanza en la prueba, por lo que me genera dudas como test de evaluación de la memoria en sentido estricto (4).

Decía antes que cada ítem recibe dos puntos (5), cuando el sujeto responde correctamente en el primer intento (dentro de los 20"), aunque también puede obtener un punto, lo que suponen dar una segunda oportunidad  en caso de fracaso en la primera (en este caso el tiempo disponible es de 10"), pero no en caso de omitir la respuesta transcurridos los 20". Esto dificulta es estudio de los baremos de corrección para el análisis de los resultados normativos en función del ítem, pero también incrementa las dudas sobre el propio test como prueba de memoria al intervenir de nuevo variables perceptivo-atencional y, ahora además, también de estrategias de respuesta (6).

Igual que existen ítem de inicio en función de edades, en cuanto a la puntuación, los baremos están especificados para periodos invariables de 4 meses, a partir de los 3:00-3:03 años. Estos cortos intervalos en edades tempranas intentan ofrecer estimaciones precisas en función del criterio edad, pero los datos empíricos de las puntuaciones no parece justificar estos intervalos tan breves, especialmente a partir de la edad de 7:00 años, si bien los datos sí parecen indicar que son pertinentes para edades tempranas, justamente aquellas en las que es dudoso que el uso del test sea pertinente. Posiblemente intervalos de edad más amplios (¿6 meses?) en las edades superiores aportarían la misma información evolutiva, simplificando el procedimiento de puntuación de la prueba.

Lo que más me interesa es contribuir al análisis del test desde la perspectiva de la evaluación centrada en el conocimiento de la causalidad de las dificultades de aprendizaje. Esto no supone renunciar al modelo normativo (del que se debe partir, repito) pero éste sólo permite el rendimiento del sujeto en relación al grupo normativo (7).

Desde esa perspectiva, en primer lugar categorizo este test como de input visual (frente a input verbal), de estímulos discretos (estímulo único) y de memoria a corto plazo (8). Los contrastes y comparaciones con otras dimensiones de la memoria requieren aplicar otras pruebas, pero esta primera categorización nos facilita tomar decisiones sobre el uso de este test en función de que lo que deseamos conocer (evaluar) se ajusta con lo que el test nos aporta. Más aun si tenemos en cuenta lo que no se explica en la documentación consultada, pero que  sí considero relevante para un uso estratégico del test: me refiero al análisis cualitativo de los estímulos y su  análisis como complemento del que deriva de los resultados normativos.

Como test referido a norma, se espera de RIAS-MnV, además valores adecuados de fiabilidad y validez, el cumplimiento estricto de los criterios normativos: que los valores Moda, Mediana y Media sean coincidentes y que la distribución de las frecuencias se ajuste a la curva normal (campana de Gaus), con lo que conlleva de ajuste entre puntuaciones y frecuencias, así como que los ítem estén debidamente ordenados en función de su índice de dificultad.

Bajo esos supuestos podemos considerar fiables los valores Promedio y Desviación típica, lo que permite el cálculo de la puntuación típica y su conversión a puntuación tipificada, tanto la que se usa en los baremos de la prueba, como en otras escalas, lo que nos permitirá establecer comparaciones con otras pruebas que se expresan en otras escalas (9), facilitando así la correcta definición de perfiles aptitudinales.

El supuesto de posicionamiento de los ítem según nivel de dificultad facilita el análisis de los mismos, tanto en términos cuantitativos como cualitativos, definiendo así niveles competenciales esperados en función de la edad del sujeto y las características de los ítem.

En esta línea, el análisis de los materiales que aporta RIAS-MnV nos permiten identificar cuatro categorías de ítem, las cuales, además de informar sobre qué criterio se emplea en la prueba para aumentar la varianza, responde al proceso evolutivo de la capacidad de memoria no verbal a corto plazo. En este sentido, se aprecia un incremento de la dificultad que responde adecuadamente al recorrido etario de la prueba, aunque no en todos los intervalos de edad parece justificado establecer baremos específicos (10). Esas categorías pueden definirse en función del estímulo y diferenciarse al menos en dos niveles de dificultad teórica, correspondiendo...

  • al nivel básico los estímulos más simples, bien de tipo "dibujo" (Categoría 1) o bien de figuras geométricas (Categoría 2) unitarias o en combinaciones simples.
  • y nivel superior, formado por estímulos más complejos, bien por el número de figuras y sus combinaciones (Categoría 3), bien por presentar combinaciones de elementos simples pero numéricamente elevados (Categoría 4).

Este gráfico muestra (en porcentajes) el peso de cada categoría respecto al total; pudiendo observar cierto equilibrio entre los dos niveles de dificultad teórica (primero - 41%, segundo - 59%), aunque con predominio del nivel 2 y en cuanto a categorías, la Categoría 3 (amarillo en el gráfico) destaca sobre el resto (31,82% del total).

Muestro en las imágenes que siguen un ejemplo de cada categoría y analizo su presencia en el test, teniendo en cuenta su posición en el listado de ítem, en el que se posicionan en bloque compacto, sólo roto por la presencia de dos elementos de la categoría 3.

Categoría 1. 

Los ítem que forman parte de esta categoría (8), teóricamente los de menor índice de dificultad representan el 18,2% del total y se posicionan al inicio de la prueba (ítem 2-9), con bajo nivel de discontinuidad, salvo uno de ellos (el 20) que, por su posición, se puede considerar deslocalizado.

Esta categoría nutre el nivel bajo de rendimiento (< T 40) en todos los grupos etarios a partir del intervalo 3:8-3:11, por lo que no se puede considerar relevante para explicar la varianza, pero puede ser relevante para la detección de dificultades significativas de memoria a corto plazo. 

Categoría 2.

Los ítem que forman esta categoría (10) suponen el 22,7% del total, se presentan predominantemente en la primera parte del test, pero no de forma continua (como sí lo hacen los de la categoría 1), sino  interpolados con los de la categoría 1 y, más frecuentemente con los de la categoría 3.

Este conjunto de ítem resulta relevante para niveles medios de rendimiento hasta 4:11 años y mantienen cierto peso en este mismo nivel intermedio de rendimiento hasta los 6:11 años. Para edades superiores es de suponer que lo son para niveles bajos de rendimiento.

Categoría 3.

Como dije antes son los más numerosos (14) y representan cerca del 32% del total. Su posicionamiento en la prueba es similar a los de la categoría 2, con la que se intercalan, aunque tienden a una mayor continuidad en las posiciones intermedias del recorrido de los ítem. También dos de ellos se encuentran deslocalizados en posiciones finales, dentro del bloque de la categoría 4.

Esta categoría tiene un papel similar a la anterior en cuanto al nivel de rendimiento que parece definir y las edades, aunque presenta mayor centralidad, por lo que, al contrario de la categoría 2, conserva esta posición clave para el nivel medio de rendimiento en edades superiores hasta los 8:11 años, edad a partir de la cual se posiciona, junto con las inferiores, como relevante para identificar niveles bajos de rendimiento. 

Categoría 4.


Son sin duda los de mayor nivel de complejidad como estímulos y se puede presumir que también de mayor nivel de dificultad, dado su posicionamiento en la serie de ítem (a partir del elemento 31) y en bloque, salvo la intrusión de dos elementos de la categoría 2.

La categoría 4 es determinante como indicador de niveles de rendimiento superiores a partir de los 5:11 años, edad en la que pasa a formar parte de puntuaciones teóricas de nivel medio, manteniendo esta función hasta agotar los grupos etarios analizados (4:11 a 12:11) 

Estos análisis que preceden son de carácter teórico-hipotético, por lo que deberán ser contrastados a nivel empírico, Su interés es facilitar la elaboración de perfiles de rendimiento en función del tipo de ítem, los cuales pueden ser útiles para entender las diferencias entre los resultados esperados y los que obtiene un alumno.

Pero no son los únicos que podemos realizar. Propongo a continuación otro tipo de análisis complementario, esta vez basado en el posible significado psicológico de las puntuaciones. Sabemos que en RIAS-MnV un ítem puede recibir tres puntuaciones: 2, 1 ó 0, y que esto afecta al recorrido de ítem que realice hasta alcanzar el criterio de finalización. Este análisis toma en cuenta la incidencia de los factores perceptivo-atencionales en los procesos mnésicos que teóricamente evalúa esta prueba, dado que aquellos son indisociables de éstos.

Entonces cabe la posibilidad de comparar el perfil de resultados teóricos (dos puntos por ítem) con el real, ya que el test no distingue entre un sujeto que obtiene 20 puntos y resuelve correctamente 10 ítem, que quien obtiene la misma puntuación pero resuelve 20 ítem con 20 fallos en primera opción, pero 20 aciertos en la segunda (11).

Lo que propongo es comparar la puntuación real (la que determina el valor T que obtiene el sujeto), con la que obtendría bien por eliminación de los ítem que puntúa 1 o por incremento a puntuación 2 de cada uno de esos ítem (12), ambos en términos de ganancia-pérdida en puntuaciones T.

Esta diferencia (13) nos permite valorar la posible incidencia de los factores perceptivo-atencionales en los resultados del test. Debe entenderse como valor aproximado; sólo tiene sentido si existen datos procedentes de otras fuentes que indiquen una posible dificultad atencional (14) y se deben contrastar con evaluaciones específicas de las capacidades perceptivo-atencionales. Además es necesario que el perfil de respuestas del alumno cumpla determinados requisitos, como, por ejemplo, que el número de ítem con puntuación 1 alcance cierto peso porcentual en el total de ítem resueltos por el alumno (15). Por eEste peso puede tomar como referencia la comparación entre el número de ítem que resultaría de no observarse ninguna puntuación 1 y los que realmente resuelve.


NOTAS

(1) Hablaremos de la escala RIAS en otro momento, aunque por ahora me limitaré a uno de sus test, el de memoria no verbal (MnV). De momento [te dejo aquí enlace] a la información disponible sobre esta escala en TEA Ediciones, editorial especializada que la comercializa en España.
(2) Estoy pensando, por ejemplo, en la aplicación de todos los ítem inferiores al de inicio en función de la edad del sujeto, cuando nos interesa conocer el rendimiento concreto de un alumno en función de las características del ítem. La puntuación T se calculará en función de la PD que resulte de la aplicación normativa, para lo que es conveniente iniciar la prueba por el ítem normativo, evidentemente, así como cumplir el criterio de retroceso cuando sea pertinente. Esto garantiza que podamos puntuar el test según criterio normativo. La aplicación del resto se realizaría en un segundo momento. Esta es una de las opciones, pero caben otras que puedes concretar según los objetivos que te plantees.
(3) Hasta donde yo se, no hay estudios al respecto y la documentación del test no aporta datos, por ejemplo, sobre el índice de dificultad del ítem. Se echa en falta.
(4) Como es sabido, todo test de memoria evalúa necesaria y con frecuencia implícitamente (esto es: sin que se explicite ni controle su incidencia real) también las capacidades perceptivas y atencionales. En eso RIAS-MnV no es una excepción. Pero es muy probable que las características del test (incluyendo el tiempo de exposición del estímulo en relación con la dificultad perceptivo-atencional que presenta) acentúe el peso de estos factores en los resultados de la prueba. Propongo que, al menos en caso de puntuaciones inferiores a promedio (2 o 1,5 Dt por debajo de T 50, por ejemplo) sería conveniente una evaluación específica de esas variables a fin de no realizar interpretaciones erróneas en términos de déficit mnésico, cuando puede serlo de tipo perceptivo-atencional.
(5) De ahí que siendo 44 los ítem, sea 88 la puntuación máxima.
(6) Con independencia de que debemos cumplir las normas de puntuación para interpretar normativamente los resultados, este sistema de puntuación, además de complicar la aplicación de la prueba al examinador (algo que personalmente no lo veo justificado), "premia" de algún modo (y disimula también) las limitaciones perceptivo-atencional; pero lo que considero es aun más negativo en cuanto que puede incidir en la puntuación del sujeto, es que favorece la respuesta al tanteo (de forma moderada), y sobre todo, la respuesta por aproximación ("si no es éste, es este otro"). No obstante, lo que en principio puede ser un "defecto", se puede convertir en un dato interesante para analizar la incidencia de los procesos perceptivo-atencionales y/o del recurso del alumno a estrategias de "descarte". En ese caso puede ser conveniente modificar de forma específica las norma de finalización, aunque sólo con fines bien definidos, sin que repercuta en la PD del test.
(7) Y con todas las cautelas que derivan de utilizar esa referencia, incluyendo la incidencia de los estadísticos relativos al margen de error de la prueba, el significado de los intervalos de puntuación y el establecimiento de indicadores de dificultad o de alto rendimiento en términos de desviación respecto a las puntuaciones del intervalo central.
(8) Aunque se usan ambos términos de forma indistinta, la memoria de trabajo (MT) debe entenderse como la operatoria que se realiza sobre la información contenida en el almacén de memoria a corto plazo (MCP). En este sentido se podrían diferenciar al menos distintos niveles de complejidad operativa en función de lo que se requiera hacer con la información contenida en dicho almacén. RIAS-MnV exige únicamente la comparación del ítem observado como estímulo con los presentados como opciones de respuesta, lo que se puede calificar como exigencia operativa básica. El incremento en el nivel de dificultad (del cual no tenemos más que indicadores indirectos), aunque empíricamente evidente, está en función de los procesos perceptivo-atencionales, especialmente de velocidad de procesamiento perceptivo-visual (aunque no sólo). Test como dígitos (WISC) permiten comparar operaciones simples con operaciones de mayor nivel de exigencia en términos de MT: dígitos en orden directo y dígitos en orden inverso.
(9) Por ejemplo en CI, puntuación escalar o decatipo. Esto nos permite comparar niveles de rendimiento en diferentes capacidades y ámbitos del desarrollo.
(10) Con independencia del uso de los baremos para la correcta puntuación del test, a fin de obtener un resultado ajustado a norma, otros análisis (que consideremos posibles y/o necesarios) no tienen necesariamente que ajustarse a esas referencias normativas, como tampoco los criterios de puntuación del ítem y de categorización de los resultados de cuerdo con los que propone el test. Digamos que el primer análisis debe ajustarse estrictamente a norma, pero que podríamos considerar pertinente un segundo (e incluso un tercer nivel de análisis), que estaría(n) justificado(s) en función de nuestras hipótesis de trabajo y de que los propios resultados del sujeto lo permitan, que podría aportar (y esta sería su principal justificación) información cuantitativa y/o cualitativa relevante para la determinación de las necesidades educativas del alumno.
(11) Es una forma exagerada de exponer la cuestión, pero refleja de forma extrema el problema que aquí se expone.
(12) Las puntuaciones 0 podrían tener el mismo tratamiento, pero en la mayoría de los casos pueden tener un significado psicológico diferente. Personalmente con considero pertinente tratarlos del mismo modo que los ítem con puntuación 1. En todo caso, lo más prudente es observar el perfil real del sujeto y tomar decisiones respecto al modo de proceder. Esto nos lleva a una segunda cuestión que también es de interés: qué perfil de aciertos (2 ptos), aciertos parciales (1 punto) y errores (0 puntos) presenta el alumno, qué incidencia tienen los 2º y 3º en el total de ítem procesados y en qué medida se incrementan éstos respecto a lo que sería un recorrido de ejecución teóricamente ajustado a los planteamientos teóricos del test.  
(13) Que se debe interpretar en positivo o en negativo, según la opción elegida.
(14) Por ejemplo, informaciones aportadas por el profesorado u otras fuentes.
(15) Por ejemplo, este peso porcentual puede tomar como referencia la comparación entre el número de ítem que resultaría de no observarse ninguna puntuación 1 y los que realmente resuelve.

jueves, 18 de julio de 2024

Procedimientos. Datos.

Calc. Borrar hojas.

Cuando el docap basado en Calc contiene una serie de hojas que nos interesan en un determinado momento, pero que resultan innecesarias una vez aplicado, resulta conveniente borrar las que no sean necesarias.


En este caso, siguiendo a Mauricio Baeza (1), para borrar hojas disponemos de la función removeByName(Nombre), que contiene el parámetro Nombre, lo que indica que el borrado está determinado por la identificación del nombre de la hoja. Un ejemplo

Sub BorrarHojaNombre

Dim oHojas As Object

oHojas = ThisComponent.getSheets()
oHojas.removeByName( "HojaFinal" )
End Sub

Como puedes imaginar, no es posible borrar una hoja que no exista (hacerlo provoca error del sistema), por lo que es conveniente controlar que se cumple dicha condición mediante un condicional asociado al método  oHojas.hasByName().

También podemos borrar la hoja activa, en la que previamente deberemos estar situados.

Sub BorrarHojaActiva

Dim oHojas As Object
Dim oHojaActiva As Object

oHojaActiva = ThisComponent.getCurrentController.getActiveSheet()
oHojas = ThisComponent.getSheets()
oHojas.removeByName( oHojaActiva.getName() )
End Sub

Dado que un libro debe contener al menos una hoja, si sólo tiene una o si hemos borrado previamente todas las anteriores, al intentar borrar esa única hoja el sistema dará error. 

Podemos controlar ambos errores (nombre de hoja inexistente o intento de borrado de hoja única) introduciendo las siguientes instrucciones en un condicional:

If oHojas.hasByName( sNombre ) And oHojas.getCount()>1 Then
oHojas.removeByName( sNombre )
Else
MsgBox "La hoja no existe o solo queda una"
End If

NOTAS

(1) Mauricio Baeza Servin (2007). Aprendiendo LibreOffice Basic. Documento modificado en septiembre de 2014.

Procedimientos. Datos.

Calc. Crear hojas (b).

Además de lo [ya visto] sobre el tema, todavía quedan algunas cuestiones por explicar en lo que a la creación de hojas se refiere. En esta entrada retomaremos algunas cuestiones y trataremos sobre otras que son de interés para la automatización del manejo de hojas mediante OOo Basic.


Como dice Mauricio Baeza (1), para crear o insertar una hoja utilizamos el método InsertNewByName(Nombre,Posición). Los dos parámetros nos permiten dar nombre a la hoja y posicionarla respecto al conjunto existen. Un script de ejemplo (2):

Sub InsertarUnaHoja
Dim oHojas As Object
oHojas = ThisComponent.getSheets()
oHojas.insertNewByName("Hoja2", 1)
End Sub

El problema de este modo de crear una nueva hoja es que es un procedimiento único, debido a que no pueden existir más de una hoja con el mismo nombre. El parámetro posición no supone esa limitación, pero modifica la posición de las hojas creadas si se sitúa por delante de ellas.

Para crear un número de hojas sin incurrir en la limitación anterior, deberemos manejar el parámetro Nombre como un string resultante de una concatenación de cadenas, siendo la segunda de ellas un valor numérico incremental convertido a string mediante la función CStr(). Por ejemplo:

Sub InsertarVariasHojas
Dim oHojas As Object
Dim i As Integer
oHojas = ThisComponent.getSheets()
For i = 0 To 3
oHojas.insertNewByName("Hoja" & CStr(i),i)
Next
End Sub

Creamos tantas hojas como deseemos mediante un bucle For, utilizando la variable Integer i como índice que aplicamos tanto en el parámetro Nombre ("Hoja" & CStr(i)), como al parámetro Posicion. De este modo no se repite el mismo nombre de la hoja, evitando así el error de sistema.

Finalmente podemos insertar una hoja al final del conjunto existente de forma automática, esto es: dando por supuesto que desconocemos el número de hojas que contiene el libro Calc.

Sub InsertarHojaFinal

Dim oHojas As Object
Dim oHoja As Object
Dim sNombre As String

sNombre = Trim(InputBox("Nombre de la nueva hoja"))

If sNombre <> "" Then
oHojas = ThisComponent.getSheets()
If Not oHojas.hasByName(sNombre) Then
oHojas.insertNewByName( sNombre, oHojas.getCount() )
End If
oHoja = ThisComponent.getSheets.getByName(sNombre)
ThisComponent.getCurrentController.setActiveSheet(oHoja)
End If

End Sub

En este caso pedimos al usuario el nombre la hoja mediante InputBox (sNombre = Trim(InputBox("Nombre de la nueva hoja"))) y comprobamos que el usuario introduzca un nombre  mediante un condicional If (If sNombre <> "" Then). También comprobamos mediante condicional que el nombre de la hoja no se repite  (If Not oHojas.hasByName(sNombre) Then). El posicionamiento (al final) se consigue mediante el método getCount() que devuelve el número de hojas del libro. Finalmente nos posicionamos en ella (oHoja = ThisComponent.getSheets.getByName(sNombre)) y la convertimos en la hoja activa (ThisComponent.getCurrentController.setActiveSheet(oHoja))

NOTAS

(1) Mauricio Baeza Servin (2007). Aprendiendo LibreOffice Basic. Documento modificado en septiembre de 2014.

(2) Este procedimiento [ya se explicó aquí], pero conviene insistir en él para la mejor comprensión de lo que sigue.

lunes, 15 de julio de 2024

Procedimientos. Macros.

Vincular macros o script a un objeto (2)

Además de un comando o a una hoja, también podemos asignar una macro/script a un objeto figura o imagen. Aunque aquí nos basemos en Calc, esa posibilidad activar un script no se limita a este servicio, ya que es posible insertar una forma o una imagen en cualquiera de los servicios LibreOffice.



Después de implementar una forma (Insertar | Forma) y/o una imagen (Insertar | Imagen) en la hoja, hacemos clic derecho sobre ella para seleccionara. Automáticamente se despliega un menú de opciones, dentro de las cuales tenemos la opción Asignar macro.


Haciendo en ella accedemos a un submenú donde se diferencia una ventana superior donde se identifica la única opción de evento disponible (Botón del ratón presionado). En la ventana inferior se encuentran los subdirectorios que contienen las distintas ubicaciones de macros posibles (Macro de). Deberemos hacer clic en aquella que contenga la macro que deseamos asociar a la forma/imagen y seleccionarla en Macros existentes.


Una vez seleccionada la macro/script deberemos hacer clic en el comando Asignar (lateral derecho de la ventana) y después en Aceptar (marco inferior). Estas dos acciones son necesarias para que se realice correctamente la asignación de la macro/script al objeto forma/imagen.


El documento Calc que ejemplifica este proceso consta de dos hojas: en la primera he implementado una figura y en la segunda una imagen. Los script (podemos decir, de ida y vuelta) permiten acceder uno a Hoja2 y otro a Hoja1. De este modo, al hacer clic en el cuadrado azul (Hoja1) nos desplazamos a Hoja2 (previamente se muestra esta hoja y después se oculta Hoja1). El proceso que desarrolla el script asociado a la imagen situada en Hoja2 realiza el proceso contrario.

Documento. En [este libro Calc] puedes encontrar ejemplificado el proceso descrito en la entrada, incluyendo los dos script que se activan desde los objetos gráficos insertados en sus dos hojas.





Procedimientos. Macros.

Vincular macros o script a un objeto (1)

Una vez que hemos creado una macro o un script, necesitamos hacer que funciones. La primera alternativa consiste en utilizar las opciones de la interface del servicio (Herramientas | Macros | Ejecutar macro), solución simple y funcional pero poco atractiva a día de hoy. La segunda consiste en asignar la macro/script a un comando de formulario (botón), que es la forma que más se asemeja al modo standard de trabajar con las interfaces visuales. Pero aun hay otras opciones.


Una
forma un tanto especial y específico de las hojas de cálculo, consiste en asociar el script a la propia hoja. Para ello nos posicionamos en el navegador inferior de Calc y hacemos clic derecho sobre el nombre de una de las pestañas, la que representa la hoja a la que queremos asignar el script. 


Se visualiza la ventana emergente con el menú que vemos en la imagen superior y seleccionamos la opción Eventos de hoja. Haciendo clic en ella, accedemos a una ventana de selección de opciones de vinculación (eventos) (1)


Seleccionamos uno de estos eventos y  hacemos clic en Macros. A continuación podremos seleccionar la macro/script que nos interesa vincular a la página, seleccionarla y hacemos clic en Aceptar.


 
Nos devuelve a la ventana anterior (ahora con la macro seleccionada identificada en la columna Acción asignada) y volvemos a hacer clic en Aceptar.

De este modo la macro/script queda vinculada a la página en función del evento que hayamos escogido.

En el ejemplo que desarrollo como concreción del proceso anterior, he elegido el evento Activar documento y la macro Main. Esto implica que cuando Hoja1 sea la hoja activa se pondrán en marcha las instrucciones que contiene este script.

Sub Main

Dim oHoja As Object

oHoja = ThisComponent.getSheets.getByIndex(1)
oHoja.isVisible = True
Wait 500
oHoja = ThisComponent.getSheets.getByIndex(0)
oHoja.isVisible = False
Wait 500
oHoja = ThisComponent.getSheets.getByIndex(2)
oHoja.isVisible = True
Wait 500
oHoja = ThisComponent.getSheets.getByIndex(1)
oHoja.isVisible = False
Wait 500
oHoja = ThisComponent.getSheets.getByIndex(3)
oHoja.isVisible = True
Wait 500
oHoja = ThisComponent.getSheets.getByIndex(2)
oHoja.isVisible = False

End Sub

En resumen, se visibiliza (mostrar) una hoja, se espera 500 msg y se oculta la hoja precedente (2), con lo que la hoja visible pasa a ser también la hoja activa (3).

Documento. Este [libro Calc] contiene el código anterior asociado a Hoja1. Al abrir este documento, nos encontramos posicionados en Hoja4. Si nos desplazamos "manualmente" a Hoja1 se desarrollará el proceso esperado (4). 

NOTAS

(1) Si comparas los eventos posibles con los que se despliegan cuando trabajamos con el control de formulario Botón (Comando), verás que los eventos de hoja son mucho más limitados.
(2) Esto es así por trabajar con el índice de las hojas, lo que facilita la secuencia Mostrar-Ocultar.
(3) Este script contiene la instrucción Wait cuyo uso merece más atención de la que se le presta aquí. Será necesario analizarla específicamente en una entrada específica.
(4) Dado que se ocultan todas las hojas (menos Hoja4), para volver al estado inicial deberemos mostrar todas las hojas (Hoja | Mostar la hoja, seleccionamos todas las que se nos muestran y clic en Aceptar), pero mantendremos Hoja4 como hoja activa. Si guardamos el documento posicionándonos en Hoja1, de modo que al volver a activarlo estemos posicionados en ella, no se activará el script.

domingo, 14 de julio de 2024

Procedimientos. datos.

Posicionarse en una hoja mediante OOo Basic

Con OOo Basic podemos trabajar sobre cualquier hoja del libro Calc con independencia de que sea sobre la hoja activa o sobre cualquiera de las demás. Eso supone una importante ventaja a la hora de crear un docap; pero muchas veces necesitamos posicionarnos visualmente sobre una hoja determinada. Mediante macros ya sabemos resolver este problema, pero también es conveniente hacerlo desde un script. En esta entrada vamos a aprender cómo.


Ya hemos visto [cómo trabajar con las hojas] de un libro Calc, pero esta opción no nos facilita visualizar la hoja (convertirla en la hoja activa), salvo que estemos trabajando sobre ésta. Para resolver esta dificultad hemos recurridos hasta ahora a una subrutina basada en macro, pero necesitamos hacerlo directamente desde un script OOo Basic. Veamos cómo esto es posible.

En principio podemos hacerlo identificando la hoja que deseamos visualizar (convertir en hoja activa) bien por su nombre, bien por su índice. El procedimiento es muy similar, en lo fundamental, así que explicaré una de las dos formas (por el nombre) y, sobre ese mismo script, indicaré las modificaciones que hay que realizar para acceder por el índice de la hoja.

Sub Ir_Hoja2Nombre ' Por el nombre

Dim DocCalc As Object
Dim Hoja As Object
DocCalc = ThisComponent
Hoja = DocCalc.getSheets().getByName("Hoja2")
DocCalc.CurrentController().SetActiveSheet(Hoja)
End Sub

Declaramos dos variables (DocCalc y Hoja), ambas de tipo Object, para asignar respectivamente el objeto documento Calc a la primera (DocCalc = ThisComponent) y el objeto Hoja a la segunda (Hoja = DocCalc.getSheets().getByName("Hoja2")); además identificamos es ésta a la hoja por su nombre mediante el método getByName() (.getByName("Hoja2")) (1)

Ya sólo nos falta convertir esa hoja seleccionada del libro en HojaActiva; para ello está la instrucción DocCalc.CurrentController().SetActiveSheet(Hoja). Con ella...
  • mediante el método CurrentController() del objeto DocumentoActual (ThisComponent) que hemos asignado a la variable DocCalc (DocCalc.CurrentController())...
  • implementamos a su vez el método SetActiveSheet(), que permite asignar la condición de HojaActiva al valor del parámetro asignado, que no es otro que el contenido en la variable objeto Hoja (SetActiveSheet(Hoja))
Si queremos realizar esta misma operación a partir del valor índice de la hoja, modificaremos la asignación de objeto a la variables Hoja, sustituyendo el método getByName() por el método .getByIndex() (2)

Documento. En [este libro Calc] encontrarás el código explicado en la entrada. En realidad contiene dos script: uno basado en el nombre de la hoja y otro en su valor índice.

NOTAS

(1) En nuestro caso, la hoja llamada Hoja2. Sin duda te habrás percatado de la posibilidad de convertir este script en una subrutina, transformado el nombre de la hoja en su parámetro. 
(2) Al que pasamos un valor numérico como parámetro, en nuestro caso, por mantener la similitud con el script anterior, ese valor es 1.

Procedimientos. Datos

Mostar y ocultar hojas mediante OOo Basic

Ya vimos como trabajar con macros para mostrar, ocultar y posicionarse en una hoja determinada. Ahora tenemos que aprender a realizar estas mismas operaciones usando OOo Basic, esto es: sin recurrir a Grabar macro.


Empiezo por exponer el código Mostar vs. Ocultar hojas por su mayor simplicidad y por ser ambos expresiones de una misma instrucción. Aunque podemos diferenciar formas alternativas de hacer lo mismo, en realidad todo forma parte de una unidad de programación.

Empecemos por ocultar la hoja activa:

Sub OcultarHoja1 'Hoja activa

Dim oHojaActiva As Object

oHojaActiva = ThisComponent.getCurrentController.getActiveSheet()

oHojaActiva.isVisible = False

End Sub

Una vez que asignamos el objeto HojaActiva a la variable objeto declarada a tal fin (oHojaActiva = ThisComponent.getCurrentController.getActiveSheet()), simplemente tendremos que declarar su atributo isVisble como False (oHojaActiva.isVisible = False)

Esta última acción es la define lo nuclear del código OOo Basic que nos permite definir una hoja como visible u oculta. Podemos crear código que parta de otras consideraciones respecto a la hoja de referencia, pero lo fundamental está ya expresado en el script anterior. 

Por ejemplo, Ocultar/Mostar una determinada hoja identificada por su índice:

Sub OcultarHoja2  'Ocultar hoja

Dim oHoja As Object

oHoja = ThisComponent.getSheets.getByIndex(1)

oHoja.isVisible = False

End Sub

 Sub MostrarHoja2 'Mostar hoja

Dim oHoja As Object

oHoja = ThisComponent.getSheets.getByIndex(1)

oHoja.isVisible = True

End Sub

En ambos casos se asigna a la variable el objeto Hoja 1 (1) (oHoja = ThisComponent.getSheets.getByIndex(1)) y después se atribuye valor True/False a su atributo isVisible

Es posible, pues, crear una subrutina que asuma la ejecución de la operación (mostrar vs. ocultar) con tan sólo pasarle como valor del parámetro True/False, además del identificador de la hoja sobre la que actuar. Te muestro el código de este conjunto:

Sub MostrarH  ' Script para mostrar una hoja

operaMO (True,0)

End Sub

Sub OcultarH  ' Script para ocultar una hoja

operaMO (False,0)

End Sub


Sub operaMO (vb As Boolean, nh As Integer)  'Subrutina

Dim oHoja As Object

oHoja = ThisComponent.getSheets.getByIndex(nh)

oHoja.isVisible = vb

End Sub

No es ahora necesario complicar los script, así que me limito a formularlos de la forma más simple. La subrutina es prácticamente idéntica al script mostrado anteriormente, sustituyendo los valores por los identificadores de los parámetros que, como se puede ver, son dos (operaMO (vb As Boolean, nh As Integer)

Para finalizar esta entrada me ha parecido de interés explicar cómo mostrar u ocultar todas las hojas del libro de una sala vez (2). 

El script es muy simple, ya que me limito a hacer la llamada a la subrutina. Además el parámetro que se pasa debe ajustarse al objetivo cambiando su valor (True vs. False):

Sub TodasOM                 'Script

TodasH(True)

End Sub


Sub TodasH (vb As Boolean) 'Subrutina

Dim oHojaActiva As Object
Dim oHojas As Object
Dim co1 As Long

oHojaActiva = ThisComponent.getCurrentController.getActiveSheet()

oHojas = ThisComponent.getSheets()

For co1 = 0 To oHojas.getCount() - 1

If oHojas.getByIndex(co1).getName <> oHojaActiva.getName() Then
oHojas.getByIndex(co1).isVisible = vb
End If

Next

End Sub

La subrutina tiene un único parámetro (TodasH (vb As Boolean)puesto que no es necesario especificar las hojas sobre las que se actuará, lo que sí es necesario es diferenciar los objetos Hojas (oHojas) y HojaActiva (oHojaActiva), de ahí que se declaren dos variables.

Después asignamos los objetos a las variables...

oHojaActiva = ThisComponent.getCurrentController.getActiveSheet()
oHojas = ThisComponent.getSheets()

 ... para recorrer después el conjunto de las hojas mediante un bucle For, (3) actuando sobre ellas (4). El condicional anidado If permite diferenciar la hoja activa del resto (5), ya que sobre ésta no deseamos que se realice la operación Mostrar/Ocultar (6).

Documento. En [este libro Calc] puedes encontrar el código explicado en la entrada.

NOTAS

(1) Según su índice, en este caso la hoja 1, esto es: la que ocupa la segunda posición.
(2) Al menos una hoja debe quedar visible, así que la idea es ocultar vs. mostrar todas las hojas menos la activa.
(3) Utilizamos el método getCount() del objeto oHojas para identificar el número de hojas del libro. Restamos 1 al valor que devuelve getCount() porque, como sabemos, la matriz que contiene las hojas del libro se inicia en 0. 
(4) Esto es: ocultándolas o mostrándolas en función del valor del parámetro vb. Esta operación se realiza sobre cada una de las hojas del libro (oHojas) mediante la instrucción (oHojas.getByIndex(co1).isVisible = vb), que identifica a cada uno de ellas por su índice, el cual se asocia al valor del contador (co1). Dicha instrucción está situada dentro del condicional If, ya que queda condicionada al cumplimiento del criterio que se establece en ella, y que constituye el objetivo de la subrutina.
(5) El condicional If tiene como condición True que no sean iguales (<>)el nombre de cada una de las hojas que recorre el bucle y el de la hoja activa (oHojas.getByIndex(co1).getName <> oHojaActiva.getName()). El nombre de la hoja se obtiene mediante el método getName aplicado tanto a la colección de hojas (en realidad matriz de objetos asignada a oHojas) como a la hoja activa (objeto asignado a oHojaActiva).
(6) Si prescindimos del condicional anidado en el bucle, el script funcionaría igual (no daría error) pero invariablemente, a la hora de ocultar las hojas mostraría como hoja activa la última de la colección de hojas del libro, ya que es en ella donde se posiciona el bucle en su recorrido (For co1 = 0 To oHojas.getCount() - 1)