Uno de los temas más debatidos en Omnis Studio, es como moverse a través de una lista de modo eficaz. El “blog” de Bastiaan, recogía un artículo dedicado a esto que me ha parecido muy esclarecedor, por lo que me he decido a traducirlo al castellano y publicarlo en el blog de “Experiencias con Omnis Studio”.
Por lo que debemos empezar por dar las gracias a Bastiaan Olij y a Kelly Burgess por sus aportaciones.
Desde muy temprano Omnis nos ha provisto de funciones 4GL que nos permitían buscar y seleccionar líneas en una lista, pero en Omnis Studio, disponemos de un potente método denominado $search. Por supuesto podrá seguir usando los comandos 4GL tradicionales. Sin embargo enseguida notará que puede conseguir mejores resultados si hace uso del método $search. A continuación se muestran algunos ejemplos, pero antes debemos explicar que el método $search, consta de los siguientes 5 parámetros:
- El primero, es la búsqueda en sí misma, un cálculo que será avaluado para cada línea de la tabla objeto de búsqueda. Podrá usarse “$ref” como puntero hacia la línea que está siendo evaluada.
- El segundo parámetro, determinará si la búsqueda deberá realizarse desde el principio. Si es “kTrue” la búsqueda comenzará desde la línea 1. No obstante es importante hacer notar, que si la línea actual es “0”, la búsqueda siempre comenzará desde el principio.
- El tercero nos permitirá indicar si la búsqueda deberá afectar sólo a las líneas actualmente seleccionadas o por el contrario a toda la lista. Si es “kTrue” sólo las líneas actualmente seleccionadas serán evaluadas.
- El cuarto parámetro nos permitirá marcar las líneas encontradas como seleccionadas.
- Finalmente, un quinto parámetro nos permitirá, realizar el proceso inverso al descrito en el parámetro anterior, es decir nos permite marcar las líneas halladas como no seleccionadas.
Éste primer ejemplo, nos permite localizar la línea que cumple con los criterios de búsqueda especificados:
; Siempre será necesario hacer uso de los 5 parámetros
If lvMiLista.$search($ref.MiColumna = 'Buscame',ktrue,kfalse,kfalse,kfalse)>0
; La encontré
Else
; No existe
End If
Selección de las líneas coincidentes con el criterio de búsqueda.
; Se usan los valores predeterminados para los parámetros
Do lvMiLista.$search($ref.MiColumna = 'Buscame')
Seleccionando todas las líneas.
Do lvMiLista.$search(kTrue)
Anulando la selección de todas las líneas.
; En este caso usamos un pequeño truco para anular la selección de sólo las líneas seleccionadas
Do lvMiLista.$search(kFalse,kTrue,kTrue)
Recorriendo las líneas seleccionadas.
; Aunque también es posible usar lvMiLista.$first(kTrue), poner $line a 0 nos ahorrará una línea de código
Calculate lvMiLista.$line as 0 ;; para comenzar desde el principio
While lvMiLista.$next(lvMiLista.$line,kTrue)
; Lo que quiera hacer
End While
Recorriendo las líneas coincidentes con el criterio de búsqueda, pero sin cambiar su estado actual.
Calculate lvMiLista.$line as 0 ;; para comenzar desde el principio
While
lvMiLista.$search($ref.MiColumna='Buscame',kfalse,kfalse,kfalse,kfalse)>0
; Lo que quiera hacer
End While
Y, finalmente, un interesante procedimiento que le permitirá localizar las líneas en una lista, de modo mucho más rápido que usando un $search, pero con las siguientes dos limitaciones:
- La columna objeto de búsqueda deberá contener un valor único.
- La lista deberá estar ordenada por la columna objeto de búsqueda.
Evidentemente la necesidad de tener que ordenar la lista previamente, rebajará la ganancia de rendimiento, pero si ya se han recuperado los datos ordenados o si se deben realizar muchas búsquedas, tal sobrecarga no tendrá importancia alguna, el método expuesto a continuación forma parte de una clase “table”, pero también podría estar en una clase “object” o “code”, a la que pasar la lista a tratar como un parámetro:
tTableClass.$quickSearch(char pvNombreColumna, fieldref pvValor,
int pvPrimeraLinea=1, int pvUltimaLinea=$cinst.$linecount)
--
;; Recuerde que la lista debe estar ordenada y la columna debe contener valores únicos
If pvPrimeraLinea>pvUltimaLinea ;; No hay lista
Calculate $cinst.$line as 0
Quit Method 0
End If
If $cinst.[pvPrimeraLinea].[pvNombreColumna]=pvValor
Calculate $cinst.$line as pvPrimeraLinea
Quit Method pvPrimeraLinea
Else If pvPrimeraLinea=pvUltimaLinea|$cinst.[pvPrimeraLinea].[pvNombreColumna]>pvValor ;; No está en la lista
Calculate $cinst.$line as 0
Quit Method 0
End If
If $cinst.[pvUltimaLinea].[pvNombreColumna]=pvValue
Calculate $cinst.$line as pvUltimaLinea
Quit Method pvUltimaLinea
Else If pvPrimeraLinea+1=pvUltimaLinea|$cinst.[pvUltimaLinea].[pvNombreColumna]
Calculate $cinst.$line as 0
Quit Method 0
End If
; Si se encuentra entre la primera y la última
Calculate lvLineaIntermedia as pvPrimeraLinea + ((pvUltimaLinea-pvPrimeraLinea)/2)
If lvLineaIntermedia=pvPrimeraLinea
Calculate lvLineaIntermedia as lvLineaIntermedia+1
Else if lvLineaIntermedia=pvUltimaLinea ;; ¿Podría suceder?
Calculate lvLineaIntermedia as lvLineaIntermedia-1
End If
If $cinst.[lvLineaIntermedia].[pvNombreColumna]=pvValor
Calculate $cinst.$line as lvLineaIntermedia
Quit Method lvLineaIntermedia
Else If $cinst.[lvLineaIntermedia].[pvNombreColumna]>pvValor
; Localizada en la zona alta de la lista
QuitMethod $cinst.$quickSearch(pvNombreColumna,pvValor,pvPrimeraLinea+1,lvLineaIntermedia-1)
Else
; Localizada en la zona baja de la lista
; Localizada en la zona baja de la lista
QuitMethod $cinst.$quickSearch(pvNombreColumna,pvValor,lvLineaIntermedia+1,pvUltimaLinea-1)
End If Ahora podrá hacer uso del “quicksearch”, mediante simplemente hacer un:
Calculate lvValor as 'MiValorUnico'
Do lvMiLista.$quickSearch('MiColumna',lvValor)
Do lvMiLista.$quickSearch('MiColumna',lvValor)