martes, 22 de agosto de 2023

Procedimientos. Datos.

Calc. Acceder a una hoja.

Una vez que sabemos crear y copiar hojas mediante código, deberemos aprender a acceder a ellas. Hacerlo manualmente no supone ninguna complicación, pero muchas veces necesitaremos hacerlo mediante código.


Efectivamente, acceder a cualquiera de las hojas de un libro Calc desde el propio servicio es muy sencillo: es suficiente con hacer clic en la pestaña que la identifica, la cual está situada e identificada por sus nombre en el navegador situado al final de la pantalla del libro.



Otra opción, más enrevesada pero igualmente útil, pasa por usar el menú Hoja/Navegar/Ir a la hoja


... que activa un menú emergente que presenta la lista de las hojas del libro para que elijamos la que deseemos.


Explico esto para que antes de lanzarnos a crear un script pensemos si con los recursos de Calc no es suficiente, aunque está claro que frecuentemente no será una solución satisfactoria. En ese caso debemos saber que contamos con tres posibles alternativas basadas en la creación de un script:
  • Posicionarnos "manualmente" en la hoja deseada mediante los procedimientos antes explicados y trabajar con ella como hoja activa mediante un script.
  • Trabajar con la hoja deseada mediante script pero sin desplazarnos visualmente a ella. Seguiremos viendo la hoja en la que nos encontremos.
  • Convertir la hoja seleccionada en hoja activa mediante código y, a continuación, trabajar con ella como hoja activa. 
Empezaré por la que considero la forma más simple de acceder a una hoja: hacerlo con y desde la hoja que estamos viendo en pantalla, considerándola como la hoja activa. Para ello el primer paso consiste en ubicarnos en esa hoja (por ejemplo Exped2 del ejemplo anterior) haciendo clic en su pestaña desde el navegador de Calc.

Una vez en ella, y más por asegurarnos de estar en la hoja activa y que ésta es la deseada, solicitaremos al script que nos devuelva su nombre: 

Sub HojaActiva
Dim oHoja As Object

oHoja = ThisComponent.getCurrentController.getActiveSheet()
Msgbox oHoja.getName()

End Sub

Lo bueno que tiene este modo de proceder (la función getActiveSheet()es que es sumamente sencillo de implementar y muy versátil, motivo por el que se pueden encontrar muchos script que hacen uso de esta función.

Como ejemplo de versatilidad se me ocurre recurrir al script mediante el cual copiamos una hoja y repetimos esta operación a discreción. Si esa hoja contara con un comando de acceso a un script que desarrollara x acciones en ella mediante getActiveSheet(), este comando y también su capacidad de lanzar el o los script asociados estaría disponible tantas veces como quisiéramos sin necesidad de modificar el código original, ya que se ejecuta siempre sobre la hoja activa, sea ésta la que sea.

En nuestro script de prueba, activarlo desde cualquiera de las hojas del libro no afecta a su funcionamiento, si bien la respuesta es diferente, dado que se ajusta a la hoja que en ese momento se considere hoja activa. Esto es: si estamos (físicamente) en Hoja1MsgBox devuelve Hoja1; si nos ubicamos en Exped5, ese será el nombre que devuelva MsgBox.

A pesar de la versatilidad de esta primera opción, el hecho de depender de las funcionalidades de Calc puede suponer ciertas limitaciones, siendo necesario acceder a una hoja sin que estemos físicamente en ella. En este caso no podemos usar las funciones asociadas a ActiveSheet: necesitamos otra alternativa como es acceder a la hoja elegida utilizando como referencia o identificador su índice o posición en el libro, o su nombre. Veamos como:

Sub HojaSelect

Dim oHoja As Object
Dim sHoja As String
Dim oDatosId (1) As Object
Dim sNombre As String, sApellidos As String
sHoja = "Exped1"
sNombre = "Macario"
sApellidos = "Rodríguez López"
oHoja =ThisComponent.getSheets().getByName(sHoja)
 
oDatosId(0) = oHoja.getCellRangeByName( "B2" )
oDatosId(1) = oHoja.getCellRangeByName( "B3" )

oDatosId(0).setString(sNombre)
oDatosId(1).setString(sApellidos) 
End Sub
Seguro que no se te escapa que aquí hay más (mucho más) código que el necesario para acceder a una hoja, y no te equivocas, pero me vas a permitir que por ahora me limite a explicar lo justo y necesario: cómo consigo que el script escriba lo que deseo (tema que ahora no interesa) en la hoja en que quiero que lo escriba (de esto sí va esta entrada): el "secreto" está en...

oHoja =ThisComponent.getSheets().getByName(sHoja)

... y más concretamente la función getByName(), cuyo único argumento (sHoja) aquí se concreta como Exped1 porque así lo pedimos en la asignación de valor a la variable...

sHoja = "Exped1"

...aunque que podría ser cualquier otra hoja, al igual que podría ser identificada por el valor-índice mediante la función getByIndex() contando que para ello y en ese caso, la variable sHoja mejor debería llamarse iHoja (variable Integer), ya que el índice es un valor numérico, no un string (1)

Con lo que sabemos hasta ahora ya disponemos de los recursos necesarios para que el acceso a una hoja no suponga un problema, debiendo elegir el procedimiento que mejor se ajuste a nuestras necesidades. Pero aun disponemos de una tercera opción: convertir una hoja en hoja activa y desplazarnos visualmente a ella, obviamente sin estar previamente situados físicamente en ella. Veamos este último script:

Sub ActivaPorIndice

Dim Doc As Object, sheet As Object, oHoja As Object

doc = ThisComponent

sheet = doc.Sheets.getByIndex(5)

doc.CurrentController.setActiveSheet(sheet)

oHoja = ThisComponent.getCurrentController.getActiveSheet()

Msgbox oHoja.getName()

End sub

Creo que ya adivinaste en qué consiste este script: efectivamente, convierte en hoja activa la hoja que ocupa la posición 5 (esto es: la sexta hoja del libro) y nos desplaza hasta ella (efecto de convertirla en la hoja activa). Esto es posible gracias a la combinación de estas dos acciones:

  1. Identificamos la hoja que deseamos convertir en activa: doc.Sheets.getByIndex(5)
  2. Pasamos el control (foco o cursor) a la hoja definida como hoja activa: doc.CurrentController.setActiveSheet(sheet). 
  3. Finalmente definimos como la hoja como activa: ThisComponent.getCurrentController.getActiveSheet()... (2)
  4. ... y para asegurarnos de estar donde queremos solicitamos información mediante MsgBox: Msgbox oHoja.getName() (3)

NOTAS

(1) Dada la simplicidad del cambio propuesto no me ha parecido necesario reproducir aquí el nuevo script, pero te animo a que "juegues" a trabajar con las diferentes opciones que supone este modo de trabajo.
(2) También es este caso podemos trabajar con el nombre en lugar de hacerlo con el índice. Para ello utilizaríamos la función alternativa getByName("Exped1") en sustitución de getByIndex() La misma recomendación que antes.
(3) Realmente este último paso no es necesario, aunque aquí sea conveniente a efectos didácticos.