Mostrando entradas con la etiqueta OOo Basic. Mostrar todas las entradas
Mostrando entradas con la etiqueta OOo Basic. Mostrar todas las entradas

jueves, 26 de febrero de 2026

Evaluación. Memoria

ENFEN. Fluidez verbal (III)

En esta entrada vamos a tratar con cierto detalle la configuración del procedimiento de análisis de los resultados y la propuestas de automatización del informe tal y como se plantean (inicialmente, vamos a decir ahora) en el DocAp que presenté en la entrada anterior. Pretendo desarrollar este análisis tomando como referencia, además de lo evidente (el soporte Calc el código OOo Basic disponibles), la documentación expuesta en las entradas sobre el paradigma experto-IA (ver entradas en Orient-IA).

Con este análisis pretendo reflexionar sobre hasta qué punto los sistemas de corrección y lo que en este blog se ha planteado en múltiples ocasiones al proponer recursos de evaluación comparten, en gran medida, ese enfoque de trabajo, aunque con limitaciones, deficiencias e insuficiencias añadidas.

Sobre cómo abordan las plataformas la automatización de sus análisis algo hemos dicho en entradas anteriores y algo diremos también aquí, pero el objetivo es centrarme más bien en lo que he planeado con cierta frecuencia como soluciones de automatización tipo DocAp. Cierto es, además, que esta propuesta de solución también ha bebido de esas fuentes, como no puede ser de otro modo, ya que las plataformas de corrección son referentes obligados en términos de forma y de contenido.

En cuanto a estas cuestiones, la fuente o base de conocimiento se explicita en los informes resultantes como análisis descriptivo de la prueba, siempre al inicio del documento y de forma variablemente extensa y detallada. Replicar este contenido en un procedimiento DocAp no ha ofrecido especial dificultad, aunque lo que me genera dudas es su utilidad y, por tanto, su pertinencia. A veces tengo la impresión de que este tipo de contenido sirven de poco y da la impresión de estar ahí para ocultar el escaso contenido de algunos informes. En todo caso, de tener utilidad real la tiene para el profesional (generalmente al profano poco le aporta), siendo que es precisamente éste quien (se supone) menos la necesita.

La segunda cuestión ya presenta mayor complejidad y requiere, por ello, mayor atención: me refiero a las reglas que determinan la relevancia de los datos y el modo en que éstos se analizan. Todavía no estamos aplicando procedimientos del tipo de los explicitados en esta entrada como estrategias de razonamiento, pero son la base para ese paso. Aquí, y en referencia a este DocAp (ENFEN-Fluidez) me tengo que detener ahora.

Diré, en primer lugar, que los datos relevantes son, obviamente, el número de palabras correctamente expresadas por el sujeto, datos estos que se enmarcan dentro de la edad del sujeto, puesto que el análisis está mediatizado por esa única variable. La consecuancia es que el DocAp debe recopilar esa información cuantitativa como base para realizar el posterior análisis de datos. Para ello se desarrolla el siguiente procedimiento:


Sub PuntuarPrueba

Dim oHoja As Object, oCelda As Object
Dim iEdad As Integer, iF1Pd As Integer, iF2Pd As Integer, iDif As Integer
Dim mDif(6) As Double
Dim dDifEsperada As Double
Dim iDifValora As Integer

MF1_Decatipo
MF2_Decatipo

mDif() = Array(4.98,4.53,4.91,5.63,6.15,5.77)

oHoja = ThisComponent.getSheets().getByName("Datos")
oCelda = oHoja.getCellRangeByName("B9")
iEdad = oCelda.getValue()

Select case iEdad
	Case 6
		dDifEsperada = mDif(0)	
	Case 7
		dDifEsperada = mDif(1)	
	Case 8
		dDifEsperada = mDif(2)	
	Case 9
		dDifEsperada = mDif(3)	
	Case 10
		dDifEsperada = mDif(4)	
	Case 11
		dDifEsperada = mDif(5)	
	Case 12
		dDifEsperada = mDif(6)	
End Select

oCelda = oHoja.getCellRangeByName("B10")
iF1Pd = oCelda.getValue()
oCelda = oHoja.getCellRangeByName("B13")
iF2Pd = oCelda.getValue()

iDif = iF2Pd - iF1Pd

If iDif - dDifEsperada > 0  Then
	iDifValora = 1
Else
	iDifValora = 0
End If

oCelda = oHoja.getCellRangeByName("B17")
oCelda.setValue(iDifValora)

	vHoja(0,True)
	PasoHoja (1)
	vHoja(1,False)

End Sub

Mediante este script accedemos a tres celdas ubicadas en la hoja Datos, las cuales contienen el dato edad (B9) y las puntuaciones directas de F1 (B10) y F2 (B13). Lo que sigue se desarrollar mediante llamadas a sendas funciones que calculan los valores de las PD como decatipos según los datos de baremos de la prueba. Me refiero, por ejemplo, a este script para el cálculo del valor decatipo de F1.



Sub MF1_Decatipo

Dim oHoja As Object, oCelda As Object

Dim mF16a(13) As Integer, mF17a(14) As Integer, mF18a(16) As Integer, mF19a(17) As Integer, mF110a(18) As Integer, mF111a(21) As Integer
Dim mF1() As Integer
Dim iEdad As Integer, iF1pd As Integer, iF1Decatipo As Integer, i As Integer, iF1Categoria As Integer

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

mF16a() = Array(1,2,3,4,4,5,6,7,8,8,9,9,9,10)
mF17a() = Array(1,1,1,2,3,3,4,5,5,6,7,8,8,9,10)
mF18a() = Array(1,1,1,1,2,3,4,4,5,6,7,7,8,9,9,9,10)
mF19a() = Array(1,1,1,1,2,3,3,4,5,6,6,7,7,8,8,9,9,10)
mF110a = Array(1,1,1,1,1,1,2,3,3,4,5,6,6,7,7,8,8,9,10)
mF111a() = Array(1,1,1,1,1,1,1,2,2,3,3,4,5,5,6,6,7,8,8,9,9,10)

oCelda = oHoja.getCellRangeByName("B9")
iEdad = oCelda.getValue()

Select Case iEdad
	Case 6
		mF1() = mF16a()
	Case 7
		mF1() = mF17a()
	Case 8
		mF1() = mF18a()
	Case 9
		mF1() = mF19a()
	Case 10
		mF1() = mF110a()
	Case >= 11
		mF1() = mF111a()
End Select

oCelda = oHoja.getCellRangeByName("B10")
iF1pd = oCelda.getValue()

For i = 0 To UBound(mF1())
	mF1(i)
	If i = iF1pd Then
		iF1Decatipo = mF1(i)
		Exit For
	End If
Next

oCelda = oHoja.getCellRangeByName("B11")
oCelda.setValue(iF1Decatipo)

Select Case iF1Decatipo
	Case <= 2
		iF1Categoria = 0
	Case 3
		iF1Categoria = 1
	Case 4
		iF1Categoria = 2
	Case 5
		iF1Categoria = 3
	Case 6
		iF1Categoria = 3
	Case 7
		iF1Categoria = 4
	Case 8
		iF1Categoria = 5
	Case >= 9
		iF1Categoria = 6
End Select

oCelda = oHoja.getCellRangeByName("B12")
oCelda.setValue(iF1Categoria)

End Sub

Aunque este procedimiento no sólo es válido, sino que se puede considerar el único ajustado al procedimiento normativo de análisis del test, implica también aceptar como únicamente válido el modelo clínico subyacente, lo que no es compartido por quienes consideran que la evaluación eductiva, que está orientada a la detección de necesidades específicas de apoyo educativo, se debe diferenciar de la evaluación clínica.

Además, desde una perspectiva de carácter procedimental se puede plantear que en realidad poca información y/o información poco relevente podemos sacar de un análisis como el que se deriva de la aplicación de este tipo de script.

Para finalizar con esta línea de análisis falta analizar cual es la propuesta interpretativa que se planea en estos momentos y en función de ese enfoque, la cual está contenida en el script InfoIndiv(mResultados() del módulo ModExternos, que reproduzco a continuación.



Sub InfoIndiv(mResultados() As Variant)

Dim sRuta As String
Dim mArg()
Dim oNuevoDoc As Object, oTexto As Object

Dim sDatosAlumno As String, sPresenta As String, sPrueba As String
Dim sF1presenta As String, sF1Resulta As String, sF1PDz As String, sF1DecatCat As String, sF1DeCatAnalisis
Dim sF2presenta As String, sF2Resulta As String, sF2PDz As String, sF2DecatCat As String
Dim sF1F2Compara As String
Dim sValora As String, sImplica As String
Dim sTextoInforme As String

'Crear nuevo documento

sRuta = "private:factory/swriter"
oNuevoDoc = StarDesktop.loadComponentFromURL( sRuta, "_default", 0, mArg())

'Construcción del contenido 

'Datos de identificación

sDatosAlumno = "Alumno/a: " & mResultados(0) & " " & mResultados(1) & " Curso: " & mResultados(5)

sPresenta = "ENFE. Funciones ejecutivas. Fluidez"

'Análisis de la prueba ENFEN

sPrueba = "ENFEN (Portellano, Martínez y Zumárraga (2009)) es una batería de pruebas que tienen como objetivo evaluar el nivel de madurez y el rendimiento cognitivo en actividades relacionadas con las funciones ejecutivas. " &_
		  "A nivel psicométrico, la bataría ENFEN está formada por un conjunto de test normativos, cuyas puntuaciones tipificadas se expresan como decatipos (media 5,5; Dt 2). Cada test de la prueba cuenta con un baremos por edades (de 6 años a 11/12 años), lo que nos permite transformar las PD en el decatipo correspondiente en función de la edad. " &_
		  "ENFEN también nos proporciona los estadísticos básicos de cada grupo de edad (Md y Dt), lo que permite analizar la PD del individuo en relación a los resultados medios de su grupo de edad." & Chr(13) & Chr(13) &_
		  "La Fluidez verbal se incluyen en ENFEN como proceso en el que están implicadas funciónes ejecutivas básicas, dada la incidencia de procesos atencionales y de memoria de trabajo. También es posible entender la fluidez verbal como indicador de la capacidad de acceder a la memoria verbal a largo plazo para recuperar la información verbal almacenada en ella. " &_
		  " Además también nos aporta datos relativos al nivel de desarrollo del lenguaje del sujeto." & Chr(13) & Chr(13) &_
		  "En ENFEN se hace uso de dos pruebas de Fluidez verbal, una por clave fonológica (F1) y otra por clave semántica (F2); esto permite realizar comparaciones del rendimiento en ambas en términos normativos y a nivel ipsativo. " &_
		  "A nivel normativo, los datos observados en ambos test son coherentes con los estudios realizados al respecto, mostrando la existencia de una diferencia invariablemente positiva a favor de F2, la cual se mantiene estable en el proceso evolutivo. " &_
		  "Esto se puede entender como consecuencia de la mayor dificultad de la clave fonológica en la recuperación de la información en comparación con el uso de la clave semántica; pero también en el procesamiento del contenido de la memoria a corto plazo."

'Análisis de los resultados en F1

sF1presenta = "Analizamos a continuación los resultados de " & mResultados(0) & " en la prueba de Fluidez Fonológica (F1)" & Chr(13) & Chr(13) &_
			  "La Fluidez fonológica se evalúa en ENFEN solicitando al sujeto la producción de palabras que empiecen por la letra/el sonido 'M'. " &_
			  "En ENFEN se incluye esta prueba para evaluar las funciones ejecutivas por resultar inusual la generación de palabras en base a un criterio fonológico, siendo la habitual el uso de estrategias de base léxico-semántica. Por ello esta exigencia obliga a la persona " &_
			  "a generar estrategias no habituales, requiriendo una organización eficiente de la recuperación verbal, autocontrol e inhibición de las respuestas inapropiadas. " &_
			  "Dado que se exige recuperación de información verbal, también se pone a prueba tanto el mecanismo de acceso al léxico como la propia memoria verbal a largo plazo. Además, el uso de claves fonológicas implica procesos de decodificación y codificación, fundamentales en la lecto-escritura. " &_
			  "Por todo ello la evaluación de la fluidez verbal es de interés para la evaluación de las dificultades de aprendizaje."
			  
'Valoración de la PD en F1

sF1PDz = CalculoZ("F1",mResultados(0),mResultados(8),mResultados(9))

'Valoración del decatipo del sujeto

sF1DecatCat = CatDecatipo(mResultados(11))

sF1DeCatAnalisis = "El decatipo correspondiente a la PD antes analizada es, según el baremo de su grupo etario, " & mResultados(10) & " el cual permite calificar su rendimiento como de nivel " & sF1DecatCat & "."

'Creación del texto de análisis de F1

sF1Resulta = sF1presenta & Chr(13) & Chr(13) & sF1PDz  & Chr(13) & Chr(13) & sF1DeCatAnalisis

'Escritura del contenido

oTexto = oNuevoDoc.Text

oTexto.insertString(oTexto.getEnd(),sDatosAlumno & Chr(13) & Chr(13), False)
oTexto.insertString(oTexto.getEnd(),sPresenta & Chr(13) & Chr(13), False)
oTexto.insertString(oTexto.getEnd(),sPrueba & Chr(13) & Chr(13), False)
oTexto.insertString(oTexto.getEnd(),sF1Resulta & Chr(13) & Chr(13), False)
'oTexto.insertString(oTexto.getEnd(),sTextoInforme, False)

End Sub


Como puedes ver, se trata de una subrutina que genera un documento en base a Writer. Como subrutina es activada desde el script DocumentosExternos mediante la llamada InfoIndiv(mDatos()) que pasa a la subrutina el contenido de la matriz mDatos().

Esta subrutina no está completamente desarrollada (o lo está parcialmente) ya que se limita al análisis de F1, pero contiene suficiente información como para servirnos de base para este análisis.

Empezaré diciendo que aparentemente resulta más compleja de lo que sería deseable, ya que contiene un número muy elevado de variables, lo que indica que posiblemente no se haya realizado un buen análisis previo de estrategias de automatización de los datos. Sobre esta cuestión trataremos en una próxima entrada, ya que ahora interesa que nos centremos en lo que tenemos delante y la alternativa que emerga de este análisis sea suficientemente compleja como para merecer ser expuesta en una entrada diferente.

Volviendo sobre lo observable, la estructura de contenido es la siguiente: datos de identificación del sujeto + descripción de la prueba (2 niveles: general + específico) + análisis de resultados.

Los dos primeros componentes no son de mayor interés ni ofrecen dificultades de implementació, al margen de las dudas ya expuestas sobre su utilidad; pero contienen un volumen total de información nada desdeñable, especialmente en casos como el actual en el que primero se decribe la prueba en su conjunto (ENFEN-Fluidez) y después cada una de las subpruebas que la conforman (en este caso sólo F1. Fluidez fonológica). Sin entrar en el interés que estas descripciones puedan tener, lo cierto es que es muy posible que existan otras formas más adecuadas y útil de manejar toda esta información sin que resulte abrumadora (y hasta distractora) al inicio del informe.

No obstante, se presentan dudas en la tercera fase, en la que se debería concretar la implementación de las reglas de interpretación de los resultados. Es aquí donde este modelo revela sus limitaciones precisamente por la manifiesta ausencia de esas reglas, limitándose a presentar datos (sF1Resulta=sF1presenta&Chr(13)&Chr(13)&sF1PDz&Chr(13)&Chr(13)&sF1DeCatAnalisis) que resultan de la aplicación de determinads funciones como CatDecatipo() a la que llama en sF1DecatCat = CatDecatipo(mResultados(11)). Esta, y no la ausencia de análisis de F2, es la principal carencia de este script.

Esta estrategia, evidentemente muy básica, se puede denominar como "expositiva", pero ponerle un nombre no es suficiente para encubrir lo que no deja de ser la evidencia de una carencia: la falta de criterios de análisis revela la ausencia de teorización sobre la prueba y el significado de los resultados que obtenemos con ella. Implica, en definitiva, carecer de una estrategia de interpretación condicionada.

Al carecer de dicha condicionalidad no es posible identificar en el DocAp ninguna estrategia de análisis, lo que parece (y es) contraproducente con el objetivo que animó la creación del instrumento. Pero "curiosamente" se trata de una "estrategias" de uso mucho más frecuente de lo esperable: al carecer de una teorización sobre el significado de las puntuaciones o al no querer comprometerla, con demasiada frecuencia se opta por la mera exposición de los datos, especialmente en los sistemas de corrección automatizada. En ellos se puede añadir el adorno de alguna categorización, lo cual tampoco compromete gran cosa, dado que corre a cuenta del aparato estadístico de la prueba. El resto queda a la libre y profesional interpretación del especialista, expediente éste perfectamente válido en otros contextos, pero aquí simplemente útil por admitido.

Esta socorrida "solución expositiva" puede ser válida para herramientas de automatización como los sistemas de corrección on-line, lo que dice mucho sobre la utilidad real de los informes que emiten, pero no lo es cuando somos nosotros mismos los que, como profesionales y especialistas, diseñamos nuestras propias herramientas de automatización, bajo nuestros criterios y en función de nuestros objetivos. En estos casos o somos capaces de implementar procedimientos y reglas de análisis o la herramienta que creemos servirá de bien poco.

Cierto es, no obstante, que también podemos limitar conscientemente nuestro proyecto de "automatización" a explicar cuestiones generales sobre el instrumento y sus características, y a formalizar la exposición de resultados. Hacer esto puede ser un objetivo válido y suficiente para algunos y/o en determinadas circunstancias, pero evidentemente deja pendiente el pleno desarrollo de lo que el modelo experto IA promete.

La concreción de esta promesa en el caso concreto de ENFEN-Fluidez queda pendiente para la próxima entrada.

lunes, 23 de febrero de 2026

Evaluación. Memoria

ENFEN. Fluidez verbal (II)

El análisis que de ENFEN-Fluidez realizamos en la entrada anterior es justificación suficiente para el desarrollo de este DocAp, aunque no condiciona el modo en que se concrete. Explicarlo es el cometido de esta entrada.

Como recurso de evaluación, sitúo ENFEN-Fluidez en el segundo nivel de intervención dentro del proceso de evaluación; aquel que implica la intervención individualizada con el alumno, por contraposición al primer nivel o de evaluación de base grupal y/o del alumno en el contexto del aula. Cierto que la simplicidad de la aplicación de esta prueba no impide radicalmente su aplicación en el grupo, pero parece más apropiado aplicarla como parte de la evaluación individual.

Otra cosa es si podemos pensarla dentro de un contexto de colaboración con servicios clínicos externos, lo cual es perfectamente factible, pero realmente esa es una cuestión secundaria: aplicar ENFEN-Fluidez está suficientemente justificada por si misma en función de lo que aporta para la identificación diferenciada de dificultades de aprendizaje, por lo que aporta respecto a la evaluación de las capacidades de memoria verbal, y por lo que aporta para la identificación de posibles dificultades de naturaleza escolar y la incidencia en que ellas tienen factores ambientales y/o del desarrollo de procesos básicos de aprendizaje.

Aunque ambas cuestiones no dejan de tener interés para el diseño de la intervención, lo cierto es que en términos operativos, ahora resultan poco relevantes, dado el objetivo de la entrada. Corresponde, eso sí, explicar en qué consiste el DocAp.

Lo primero es decir, precisamente, que se trata de un Docap; esto es un recurso que integra una serie de procesos (que veremos después) basándose en los servicios de LibreOffice, y que es posible gracias al empleo del lenguaje OOo Basic.

Como DocAp se puede calificar como DocAp complejo dado que requiere de la intervención de dos servicios, aunque tal y como se configura podríamos identificarlo como DocAp simple, puesto que la versión que aquí presento no se ha desarrollado del todo, por lo que sólo se hace uso de Calc, quedando Writer como soporte complementario, únicamente "a modo de prueba".

La automatización es, pues, parcial, aunque lo es por motivos que explicaré en su momento; no precisamente por carecer de los medios técnicos para alcanzar niveles óptimos de desarrollo como DocAp: no culminar la lógica implícita (de automatización) es una decisión tomada conscientemente, a pesar de disponer de los medios para hacerlo. Nos quedamos a las puertas de automatizar la generación del informe de resultados (1) para dedicar una entrada específica a tratar este tema en el marco del análisis las opciones disponibles, concretamente de la viabilidad de lo que podríamos llamar de forma un tanto grandilocuente modelo experto de automatización (2).

Por eso, hasta aquí me limito a presentar en esta entrada la automatización de la aplicación y la puntuación del test, quedando pendiente el análisis de resultados y la generación del informe individualizado. Todo ello se concreta un soporte Calc que deriva de otro utilizado hace tiempo para digitalizar y recoger datos de la escala ENFEN al completo (no exclusivamente de las pruebas de fluidez). En el original no existía prácticamente automatización, pero en el actual sí, heredando en ello el modelo aplicado en una antigua versión Filemaker que sí automatizaba la puntuación, un somero análisis de los datos y la emisión de un breve informe personalizado de resultados.

El DocAp actual consta formalmente de tres hojas (Id, Pruebas y Datos), de las cuales sólo la primera está visible al abrir el documento. Pero la complejidad real del DocAp está en el código, responsable de su funcionamiento, visible desde el IDE y que contiene lo siguiente:

Como ves, se diferencian 6 módulos y 22 script. Este conjunto de elementos hace posible que se desarrollen los procesos de automatización del DocAp y que explicaré resumidamente en base a lo que la visualización de la interface permite entrever.

En hoja Id encuentras un formulario basado en celdas, destinado a recoger los datos de identificación del alumno, y lo que es la síntesis de resultados de la aplicación del test.

Además tienes dos comandos: uno (APLICAR TEST) para continuar con la aplicación de la prueba y otro (BORRAR) para borrar el contenido antiguo, si es que está aun visible. Como sabes, ambos están asociados a la ejecución de sendos script.

La segunda hoja queda accesible al activar el botón APLICAR TEST y contiene, como cabe esperar, el sistema de recogida de datos y el de puntuación del test. Ambos funcionan mediante los comandos respectivos: Contador F1 Y Contador F2 para capturar las respuestas (el número de respuestas) y PUNTUAR para realizar la puntuación del test en función de los estadísticos de la prueba.

En este caso sí me interesa detenerme en la explicación del funcionamiento de estos comandos, ya que presenta cierta diferencia respecto a los procedimientos conocidos de puntuación de la ejecución. Esto es así porque en estas pruebas de fluidez lo que nos interesa es capturar el número de respuestas correctas que emita el sujeto, y nada más. De ahí que hayamos ideado un procedimiento de contador de aciertos que se concreta en dos script, uno por cada prueba (Fonológica - Semántica) asociados a sendos comandos (aquí el script del contador F1)...



Sub ContadorF1

Dim oHoja As Object, oCelda As Object
Dim i As Integer

'Acceso a la hoja Pruebas
oHoja = ThisComponent.getSheets().getByName("Pruebas")

'Acceso a la celda contador
oCelda = oHoja.getCellRangeByName("G2")
i = oCelda.getValue

i = Contador(i)

oCelda.setValue(i)

End Sub

... y ambos script a la función Contador()

Function Contador(i As Integer) As Integer

Contador = i + 1

End Function


El comando PUNTUAR presenta un código más complejo, que conforma los tres script (un script y dos subrutinas) que contiene el módulo ModPuntuar, al que te remito: básicamente consiste en lo siguiente:

  • El comando PUNTUAR permite acceder al script PuntuarPrueba, el cual captura el valor del contador de las celdas F1 (G2) y F2 (G12) y se lo pasa a sendas subrutinas, una para puntuar cada una de las pruebas atendiendo a la edad del niño y a los datos estadísticos de los respectivos baremos.
  • Finalmente traslada los datos resultantes también a la hoja Datos.

Dada la extensión de estos script, remito al IDE para su lectura y análisis. La explicación que sea pertinente para retomar la actualización del soporte se realizará en ese momento.

Para finalizar ahora esta entrada, sólo resta señalar que la hoja Datos contiene una sencilla tabla de datos con los de identificación y los resultados de ambos test.

A partir de estos datos será posible crear una base de datos acumulativa, y desarrollar un modelo de informe de resultados, única fase de la automatización de este test que aunque ha sido desarrollada, no se muestra accesible mediante un botón de comando.

No obstante, si lo deseas y a modo de borrador, puedes generar un modelo de informe sobre Writer activando directamente el script DocumentosExternos ubicado en el módulo ModExternos.

Documento. Descarga del DocAp de la prueba

Notas:

1 En realidad también queda pendiente la generación de la base de datos, pero en este caso es más una cuestión de simplificación del procedimiento, mucho menos justificable que lo anterior.
2 Tiempo habrá de bajar expectativas, pero lo cierto es que, en esencia, es precisamente de lo que se trata aquí: ¿es posible diseñar contantemente alternativas de automatización basadas en el conocimiento (teóricamente) del experto?. ¿cuáles son realmente las alternativas disponibles?. Se comprenderá que, así presentada la cuestión, sea conveniente abordar este tema de forma específica. Bien vale una entrada... cuanto menos.

viernes, 6 de febrero de 2026

Acreditación

Modelo listado (base de datos)

Además de los procedimientos anteriores, también podemos automatizar la generación de acreditaciones basándonos en la elección de un determinado registro de una base de datos (Calc). 


Se trata de una opción basada en el uso de marcadores que tiene como peculiaridad la posibilidad de seleccionar el registro mediante la ubicación previa del cursos en el campos A del registro deseado de nuestra base de datos.

Veamos el script:

Sub TransferirDatosAcreditacion

    Dim oDocCalc As Object
    Dim oSel As Object
    Dim oHoja As Object
    Dim nFila As Integer
    Dim f As Integer
    Dim nRespuesta As Integer 
'Avisos de inicio
MsgBox "Para el correcto funcionamiento del script debe posicionarse en la celda que desee de la columna A"
MsgBox "Por favor, seleccione la primera celda de la fila para posicionarte en el registro a imprimir.", 16, "Error"
  
' 1. CONFIGURACIÓN DE MATRICES
    ' Define aquí los nombres de las columnas (solo para el mensaje) 
    ' y los nombres exactos de los marcadores en Writer.
    Dim vCampos(23) As String
    Dim vMarcadores() As String
    
    vMarcadores = Array("Curso", "fecha", "SEO", "Orienta", "NIE", "Nombre", "Apellidos", "FNac","Edad","CursoS","Madre","DNI","Domicilio","CP","Tlf","nesc","ccent","otras","nee","neae","flugar","Ffecha")
' 2. UBICAR CELDA ACTIVA
    oDocCalc = ThisComponent
    oSel = oDocCalc.CurrentSelection
    
    ' Validar que hay una celda seleccionada
    If Not oSel.supportsService("com.sun.star.sheet.SheetCellRange") Then
        MsgBox "Por favor, seleccione la primera celda de la fila para posicionarte en el registro a imprimir.", 16, "Error"
        Exit Sub
    End If
    
    nFila = oSel.CellAddress.Row
    oHoja = oDocCalc.Sheets(oSel.CellAddress.Sheet)
    
    ' 3. AVISO AL USUARIO
    nRespuesta = MsgBox("Se tomarán los datos de la fila " & (nFila + 1) & "." & Chr(13) & _
                        "¿Desea continuar?", 33, "Confirmar Registro")
    
    If nRespuesta <> 1 Then Exit Sub

 ' 4. RECORRER COLUMNAS DE CALC (Bucle 1)
 ' Guardamos los datos de la fila en una matriz temporal
    Dim nLimite As Integer
    nLimite = UBound(vMarcadores) ' Obtiene el índice máximo de la matriz
    
    Dim vDatosExtraidos(nLimite) As String
    Dim i As Integer
    
    For i = 0 To nLimite
        vCampos(i) = oHoja.getCellByPosition(i, nFila).String
    Next i
    
' 5. ACCESO A WRITER
   Dim oDocWriter As Object
   Dim oMarcadores As Object
   Dim sUrl As String
    
   ' Acceso al documento
   sUrl = convertToURL("C:\Users\acredita_writeb.ott") 'Sustituya esta dirección por la que corresponda según su organización de archivos
   oDocWriter = StarDesktop.loadComponentFromURL(sUrl, "_blank", 0, Array())
    
   If IsNull(oDocWriter) Then
      MsgBox "No se encontró el archivo de destino.", 16, "Error"
      Exit Sub
   End If

   oMarcadores = oDocWriter.Bookmarks

' 6. POSICIONAR CONTENIDOS EN MARCADORES (Bucle 2)
   For i = 0 To nLimite
    Dim sNombreMarcador As String
    sNombreMarcador = vMarcadores(i)
        
    If oMarcadores.hasByName(sNombreMarcador) Then
    ' Insertamos el dato correspondiente de nuestra matriz de datos
      oMarcadores.getByName(sNombreMarcador).getAnchor().setString(vCampos(i))
    Else
    ' Opcional: Avisar si falta un marcador (que no debería)
    MsgBox "Aviso: No se encontró el marcador " & sNombreMarcador, 48
    End If
    Next i

    MsgBox "Se han transferido " & (nLimite + 1) & " campos correctamente.", 64, "Éxito"
    
End Sub

 Acuérdate de cambiar la ruta de tu documento-plantilla acredita_writeb.ott; hazlo como ruta absoluta para evitar fallos. Para ello es suficiente con que, después de descargados los documento y reubicados en tu sistema, selecciones el documento write, hagas clic derecho sobre él y selecciones la opción "Copiar como ruta de acceso"; después sólo tienes que pegar esa ruta como alternativa a la que aparece en la línea de instrucciones del script.

Documentos. Desde aquí y desde aquí accedes a los documentos que deberás descargar. Recuerda que trabajas desde LibreOffice. 

martes, 23 de diciembre de 2025

Evaluación

Automatización de la evaluación


Análisis de la puntuación total mediante OOo Basic



Normalmente lo primero que se analiza de los resultados de la aplicación de un test es el sumatorio de las puntuaciones obtenidas, bien para convertirlas a algún tipo de escala en función de unos estadísticos, bien para compararla con un criterio de nivel de ejecución. 

En ambos casos podemos encontrarnos con datos que tienen un único y posible significado o diferente en función de determinado referente, como puede ser la edad del sujeto o su nivel o curso.

Cuando el significado es único el procedimiento que sigue no se diferencia mucho del expuesto en [esta entrada], aunque empleemos código OOo Basic en lugar de funciones Calc. Pero cuando el significado es diferente en función de, por ejemplo, la edad, previamente podemos que realizar ciertos procesos para automatizar correctamente el análisis y no tener que plantear procedimientos específicos para cada edad o contexto de referencia.

Aunque hay muchos, el test PLON-R. Fonología es un ejemplo de lo que acabo de exponer: una misma puntuación total o directa (PD) tiene significados diferentes en función de la edad. Por ejemplo, obtener 21 ptos es lo esperado para 3 años, ya que indica que el niño pronuncia correctamente todos los fonemas y grupos fonémicos propios de su edad, pero es indicador de déficit para el resto de las edades. Lo mismo sucede con la PD 44, aunque en este caso es indicador de error en la aplicación del test para niños de 3 años (o de alto nivel de desarrollo fonológico), se ajusta a lo esperado para 4 años y es indicador de déficit para edades superiores.

Es por ello que antes de realizar cualquier valoración de la PD, antes deberemos ponerla en relación con la edad (en este caso). La forma de realizar esta operación de forma automatizada, sin que sea necesario explicitar conocimiento de los datos propios del grupo de referencia ni desarrollar procedimientos específicos para cada edad, es trabajar con matrices y con bucles.

Este procedimiento ya [ha sido empleado] en el tratamiento del input con otros objetivos, pero es suficientemente interesante como para que de nuevo le dediquemos nuestra atención.

Partimos del conocimiento de dos datos del sujeto: su edad y la PD que obtuvo, pero también de los posibles valores que pueden tener ambos datos. Los primeros los almacenamos en sendas variables (edad y pd) y los segundos en dos matrices; una para las edades...

Dim edades() As Integer
edades = Array(3,4,5,6)

... y otra para las PD esperadas para cada edad.

Dim ptos_max() AS Integer
ptos_max = Array(21,44,56,61)

Como puedes ver ambas colecciones de datos guardan relación (se emparejan) en función de la posición que ocupan en sus respectivas matrices: edades(0) guarda el valor (años) del primer grupo etario (3) y ptos_max(0) el valor de la PD esperada del primer grupo etario (21).

3 años -> 21 ptos en total

Precisamente en la equivalencia de posiciones de edades y valores PD está la base de automatización; gracias a ella nos podemos olvidar de los valores numéricos y limitarnos a recorrer las matrices con un bucle y a realizar comparaciones condicionales.
  • Primero. Recorremos la matriz mediante For 
For i = 0 To UBound(edades()))
  • Segundo. Localizamos el valor posicional de la edad real del sujeto y la utilizamos como primera condición
For i = 0 To UBound(edades())
If edades(i) = edad Then
    -> [Segunda condición]
End If
Next 
  • Tercero. Cuando el recorrido del bucle hace True la primera condición, lanzamos el segundo análisis condicional sobre el que realizamos la valoración de la pd del sujeto.
If pd = ptos_max(i) Then
Valoracion = "Acierto total"
Else
Valoracion = "Resultado insuficiente"
End If

Esta es la forma más simple en la que se realiza la valoración de la PD, pero posiblemente la menos común. De todas formas, es fundamental, ya que, por muy complejas que sean las demás, todas parten de la relación que establecemos mediante la estructura que hemos explicado.

Evaluación

Automatización de la evaluación

Input incremental (II)




Dado que en la [entrada anterior] establecimos previamente los diferentes soportes de interfaz para la fase input, en esta daremos un paso más y crearemos esa interfaz a partir de los datos de una matriz y en función de la edad. En este caso es así dadas las características de la prueba de referencia (PLON-R. Fonología).

No se trata de un procedimiento totalmente automatizado, ya que la hoja sobre la que crearemos la interfaz y parte de los elementos que contiene han tenido que ser creada previamente, pero lo que ahora nos interesa es la parte nuclear de su contenido: el listado de palabras que deberá producir el alumno y que deberemos evaluar nosotros.

Este modo de resolver la cuestión nos ahorra crear tantas hojas/interfaces como grupos input existan en la prueba. Así en PLON-R. Fonología resolvemos con una lo que según el procedimiento anterior precisaba cuatro. Se eliminan también unos cuantos script asociados al manejo de esas hojas.

Sub CrearLista

Dim oHoja As Object, oCelda As Object
Dim listado() As String

Dim annos As String
Dim edad As Integer

annos = al_edad()
edad = CInt(annos)

If edad > 6 Then
edad = 6
End If

listado() = copiaPal(edad)

'Acceso a la página

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

oCelda = oHoja.getCellRangeByName("B2")
oCelda.setString("Palabras")
oCelda = oHoja.getCellRangeByName("C2")
oCelda.setString("Puntos")

For i = 0 To UBound(listado())
oCelda = oHoja.getCellRangeByName("B" & i+3)
oCelda.setString(listado(i))
Next

End Sub

Pasemos ahora a analizar cómo se desarrolla esta propuesta. El primer paso consiste en acceder a la edad del sujeto, ya que ésta es la que determinará el desarrollo del resto. Para ello, desde nuestro script principal, haremos uso de la función, creada en versiones anteriores, que nos permitía acceder a ese datos (annos = al_edad()). 

Function al_edad () As string

Dim oHoja As Object, oCelda As Object
Dim i As Integer
Dim edad As String

'Acceso a Resultados para capturar la edad
oHoja = ThisComponent.getSheets().getByName("Resultados")
oCelda = oHoja.getCellRangeByName("B4")
edad = oCelda.getString

al_edad = edad

End Function

Una vez que disponemos de ese dato (string) lo convertimos a integer (edad = CInt(annos)) para operar con él (If edad > 6 Then -> edad = 6 -> End If), evitando posibles errores en el manejo de los datos de edad cuando ésta supera los 6 años.

El paso siguiente consiste en acceder a la función que nos da acceso al contenido con el que trabajar (listado() = copiaPal(edad)): el listado de palabras que corresponde por edad y que deberemos recuperar de la hoja Matrices.

Function CopiaPal(al_edad As Integer)

'para acceso a objetos
Dim oHoja As Object, oCelda As Object
Dim listaPal () As String

'Para acceso a datos
Dim i As Integer
Dim max As Integer
Dim edades() As Integer
Dim ptos_max() AS Integer

edades = Array(3,4,5,6)
ptos_max = Array(21,44,56,61)

'Calculo y establecimiento del límite superior del listado

For i = 0 To UBound(edades())
If edades(i) = al_edad Then
max = ptos_max(i)
End If
Next 

ReDim listaPal(max-1)

'Acceso a la hoja que contiene la base de datos

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

For i = 0 To UBound(listaPal())
oCelda = oHoja.getCellRangeByName("I" & i+1)
listaPal(i) = oCelda.getString()
Next

CopiaPal = listaPal()

End Function

Esta función accede al contenido de la hoja Matrices y accede al valor numérico de la extensión del listado que debe crear haciendo uso del parámetro al_edad que le hemos pasado desde el script principal, mediante una analogía entre los valores de posición de la matriz edades y los de la matroz ptos_max.

For i = 0 To UBound(edades())
If edades(i) = al_edad Then
max = ptos_max(i)
End If
Next 

Con ese dato de longitud o límite superior redimensionamos la matriz que contendrá el listado de palabras (ReDim listaPal(max-1)). Mediante un segundo bucle recorremos la columna I y accedemos a las palabras que incluimos como elementos de la matriz (listaPal(i) = oCelda.getString()) que la función devolverá al script principal (CopiaPal = listaPal()).

De regreso a éste, sólo nos queda posicionarnos en la hoja sobre la que escribir los títulos de las columnas...

oCelda = oHoja.getCellRangeByName("B2")
oCelda.setString("Palabras")

... y el listado y proceder a ello mediante el procedimiento ya conocido de asignar contenido a las celdas.

For i = 0 To UBound(listado())
oCelda = oHoja.getCellRangeByName("B" & i+3)
oCelda.setString(listado(i))
Next

Si deseáramos completar el procedimiento y dejar listo los materiales para un uso posterior deberíamos implementar código que capture el resultado de la aplicación del test (puntuación de cada ítem) para trasladarlos a la hoja Resultados, eliminando antes el contenido de la lista de palabras y de la puntuación.

A parte de este posible desarrollo del script, también nos podemos plantear otros que implican establecer un condicionamiento múltiple. Un ejemplo sobre PLON-R. Fonología podría ser seleccionar únicamente los fonemas y no los grupos fonémicos, o sólo los fonemas oclusivos, o sólo los fonemas sonoros... Los ejemplos son múltiples, tantos como variables diferenciadoras hayamos establecido. Además esas subcategorizaciones podemos establecerlas secuencialmente o mediante condicionales anidados. En cualquier caso, lo interesante es que podemos hacer uso del procedimiento básico que hemos explicado en esta entrada para automatizar la selección del contenido sobre el que trabajar en función de los criterios que nos interese aplicar en cada caso.