http://www.fpress.com/
miGrid.ZIP (N.R.: Tienes que cambiar un
path del INICIO.PRG)
En cierta ocasión me propuse hacer una clase Grid que fuera genéico. Me explico, que le pasara una tabla o el resultado de una select en un cursor al Grid y me mostrara todos los campos o parte de ellos (los que en cada caso me interese) y que cuando el usuario hiciera doble click en la línea que le interesase el Grid se cerrara devolviendo el número o el contenido del registro seleccionado.

La principal dificultad la encontraba en el doble click pues parecía que el Grid no se enteraba de que estaba pulsando sobre uno de los Textbox.
En la KB (Q128075) vi que esa forma de comportarse según Microsoft era por diseño no es que se tratara de un error o de un fallo de programación.
Microsoft dice “Este comportamiento es por diseño. Un objeto Grid es un contenedor de columnas. Las columnas contienen controles. Los métodos definidos en un Container no inhieren en la jerarquí del container. Por ejemplo, el código que incluyas en el evento Click de un formulario no se ejecuta cuando haces click en un botón de comandos.
Cuando un Grid se llena con datos y haces click en una celda del Grid, el contro, un textbox, por defecto, recibe el evento click. El Grid recibe el evento Grid en lugares que no contienen datos”.
Microsoft también apunta dos formas de solucionarlo:
a.- Poner un Shape encima del Grid pero eso no me permite saber en qué celda se ha hecho click.
b.- Escribir el contenido del Click en el textBox base: ¡Este es el camino!
Vista la idea, me puse en marcha e hice lo siguiente:
1.- Creo una clase Formulario y la llamo MiForm
2.- Creo una clase TextBox y la llamo MiText
3.- Creo una clase Grid y la llamo MiGrid
¿Pero, cómo pongo mi clase MiText dentro de MiGrid pues aparentemente no hay forma? Después de dar muchas vueltas a la KB vi que la forma de hacerlo es por código: tengo que quitar el TextBox por defecto y poner MiText mediante código y eso hay que hacerlo en el INIT de la clase MiForm.
¿Pero cómo sé cuantas columnas va a tener el Grid? Si pones un Grid con el número de columnas columncount a –1 al abrirlo crea tantas columnas como campos tenga la tabla seleccionada.
Luego el proceso tendrías que ser:
a) Abrir una tabla
b) Cargar un formulario con un Grid con el ColumnCount puesto a –1
c) En el Init del Formulario (ten en cuenta que ya se ha cargado el Init del Grid) debo averiguar cuantas columnas tiene el Grid y quitarle el textbox standard y cargar el mio personalizado
¿Pero cómo
sé cuantas columnas tiene un Grid?
Si escribes:
*-
Tienes que tener una tabla seleccionada *- antes de
*-
lanzar este código:
AMEMBERS(laTemp,
THISFORM.miGrid, 2)
FOR EACH oColumn IN laTemp
? oColumn
ENDFOR
Puedes averiguar cuantas columnas tiene el Grid añadiendole un contador y su nombre que es lo que en este caso te devuelve.
De acuerdo, ya sé cómo contar las columnas de un Grid. ¿pero, como quito el textBox estándar y pongo mi clase TextBox personalizada?. Para eso el código anterior deberías modificarlo un poco y escribir:
AMEMBERS(laTemp,
THISFORM.miGrid, 2)
FOR EACH oColumn IN laTemp
WITH THISFORM.Grid1.&oColumn
.RemoveObject('Text1')
.ADDOBJECT('NewText', 'miText')
.NewText.VISIBLE = .T.
.SPARSE = .F.
.CURRENTCONTROL = 'NewText'
ENDWITH
ENDFOR
Mmm... Esto empieza a estar interesante! ¿pero hasta ahora no hemos hecho nada del DblClick de la clase MiText y además me parece que no se pueden escribir métodos en tiempo de ejecución! Esto es un poco relativo, sí que se pueden, pero no es la materia de este artículo. En el método DblClick de la clase TextBox pondremos la acción que queremos que se ejecute y esa acción la pondremos en una propiedad:
Escribe en el método DblClick del TextBox el siguiente código:
LOCAL lcExp
lcExp = THIS.lcAccionEjecutar
IF NOT EMPTY(lcExp)
*- Ejecuta la orden
&lcExp
ENDIF
Y modifica el código del Init del Form por el siguiente:
FOR EACH oColumn IN laTemp
WITH THISFORM.miGrid.&oColumn
lcVarUna =
laTituloColum(contador)
.ADDOBJECT('NewText', 'miText')
.NewText.VISIBLE = .T.
.SPARSE = .F.
.CURRENTCONTROL = 'NewText'
.NewText.lcAccionEjecutar = 'THISFORM.Release()'
ENDWITH
ENDFOR
Y con esto ya casi tenemos todo. Como no es mucho voy a trascribir todo el código para lanzar la clase anterior para que se vea bien. De todos modos en los fuentes tienes el ejemplo completo y te bastará con ejecutar el programa de Inicio.prg para ver su funcionamiento.
***** INICIO.PRG
*********************
CLOSE ALL
CLEAR ALL
set defau to e:\foxpress\sep00\art1\
set classlib to selectora
*-
Guarda en una variable el area
*-
seleccionada actual para
*- cerrar volver a recuperarla
lcSelec = SELECT()
*- Nombre que le vamos a poner
a las columnas
LOCAL ARRAY laCabecera(2)
laCabecera(1) =
'Código'
laCabecera(2) =
'Nombre 1'
*- Campos a mostrar
Select * from tabla1 into
cursor _TmpCursor
*- Activamos el Cursor
select _Tmpcursor
*- Instanciamos la clase miForm
frmMyForm =
CREATEOBJECT("miform", @laCabecera)
frmMyForm.SHOW()
RELEASE frmMyForm
*- Mostramos el campo
seleccionado
? _tmpCursor.campo1
USE IN _TmpCursor
USE IN tabla1
*- recupearamos tabla original
seleccionada
SELECT(lcSelec)
Y ya lo tienes. Mira los fuentes para ver el ejemplo en funcionamento.. El resto queda para tu imaginación.
¡Espera, espera...! ¿Y si el usuario pulsa Enter en vez de hacer DobleClik? Pues deberías codificar el KeyPress de la clase base del Textbox.
¿ Y si la Tabla o cursor tiene muchos registros y quiero seleccionar uno entre ellos? Para eso necesitaríamos otro artículo que quizás venga en el próximo número: de momento basta con esto.
FoxPress – Septiembre de 2000
© 2000 FoxPress. All rights reserved