llevar registro de una busqueda en cursor grid a tabla en otro formulario

230 views
Skip to first unread message

Lionel Kieffer

unread,
Feb 27, 2017, 5:43:53 PM2/27/17
to Comunidad de Visual Foxpro en Español
Hola tengo una formulario donde realizo la carga de datos, eliminacion y modificación y despues otro formulario donde muestra un grid y donde realizo busquedas para llevar ese registro que encontre al otro formulario y poder modificarlos. Yo antes en el grid usaba la tabla asociada, que era la misma que en el formulario de carga y utilizaba el comando seek() para buscar. Pero vi en esta comunidad que es más seguro trabajar con cursor, en vez de la tabla en un grid y que ademas es más rápido con el comando select-sql. El problema que tengo, es que antes podia llevar el registro que seleccionaba al formulario, pero ahora como a la tabla la llevo a un cursor y ahi la filtro con la busqueda ya no puedo decirle a la tabla cual registro es, porque cambia la posicion del registro según el filtro.

Este es el nuevo código que utilizo para realizar la busqueda de la tabla datos, la llevo a un cursor y ahi la filtro. El grid es solo para buscar y llevar el registro por ende el grid tiene la propiedad Readonly=.T.

PRIVATE consulta
consulta=(VAL(alltrim(Thisform.Txtexpedni.Value)))
DO CASE
CASE Thisform.cmbBusqueda.Value="Expediente"
Thisform.grido.RecordSource = ""
SELECT * FROM datos WHERE expediente=consulta ORDER BY ingreso INTO CURSOR cur_grid readwrite
Thisform.grido.RecordSource = "cur_grid"
Thisform.grido.Refresh
IF RECCOUNT("cur_grid")>=1 Then
MESSAGEBOX("Se encontro","Consulta",64,1)
ELSE
MESSAGEBOX("No se encontro","Consulta",64,1)
ENDIF
 

CASE Thisform.CmbBusqueda.Value="DNI"
Thisform.grido.RecordSource = ""
SELECT * FROM datos WHERE DNI=consulta ORDER BY ingreso INTO CURSOR cur_grid readwrite
Thisform.grido.RecordSource = "cur_grid"
Thisform.grido.Refresh
IF RECCOUNT("cur_grid")>=1 Then
MESSAGEBOX("Se encontro","Consulta",64,1)
ELSE
MESSAGEBOX("No se encontro","Consulta",64,1)
ENDIF


CASE Thisform.CmbBusqueda.Value="Apellido y Nombre"
Thisform.grido.RecordSource = ""
SELECT * FROM datos WHERE apellido=Thisform.txtApe.Value AND nombre=Thisform.txtNom.Value ORDER BY ingreso INTO CURSOR cur_grid readwrite
Thisform.grido.RecordSource = "cur_grid"
Thisform.grido.Refresh 
IF RECCOUNT("cur_grid")>=1 Then
MESSAGEBOX("Se encontro","Consulta",64,1)
ELSE
MESSAGEBOX("No se encontro","Consulta",64,1)
ENDIF
ENDCASE

Como crea el cursor con la busqueda filtrada no puedo obtener nunca la posición real del regsitro para poder llevarla a la tabla datos y despues poder modificarla o eliminarla. No se si volver a trabajar directamente con la tabla y el comando seek o si hay alguna otra forma para trabajar con el comando select-sql y obtener el mismo resultado que antes. 

Lionel Kieffer

unread,
Feb 27, 2017, 8:28:33 PM2/27/17
to Comunidad de Visual Foxpro en Español
Buscando encontre una publicacion de Fidel Charny que se podía ubicar el registro de una tabla, con este código.
Podés tener el número de registro de manera muy fácil
select *,recno() from articulos into cursor NombreCursor
Esto agrega una última columna llamada "Exp_n", donde n coincide con el número de campo. Por lo que para saber cual es el nombre del campo, solamente tenés que hacer
lcExp
="Exp_"+ltrim(str(fcount( "NombreCursor" ) ) )
LnRegistro=Evaluate(lcExp) && devuelve el número de registro de la tabla original.
select articulos
go lnRegistro
if rlock()
   
* reemplazo de valores
 UNLOCK
ENDIF

Funciona pero en parte. Aplique el código a la búsqueda como lo dice ahi utilizando el recno() en el select
SELECT *, RECNO() FROM datos WHERE expediente=consulta ORDER BY ingreso INTO CURSOR cur_grid readwrite

y puse un boton para probar con el siguiente código
LOCAL lcExp, LnRegistro
lcExp
="Exp_"+ltrim(str(fcount( "cur_grid" ) ) )
LnRegistro=Evaluate(lcExp)
select datos
go lnRegistro
Thisformset.frm_sis_afis.refresh
RELEASE lcExp
, LnRegistro

Cuando la búsqueda da 1 solo registro como resultado no hay problema, funciona perfecto; pero cuando da 2 resultados y elijo uno hago click en el botón y va a ese registro, pero si despues de eso selecciono el segundo resultado y le hago clik para que me envie el otro registro me da este error en el módulo.

Error en el módulo : FORMSET.BUSCAR.COMMAND1.CLICK
Número de Línea No.: 3
Variable 'EXP_15' is not found.
Error Número       : 12
Fecha y hora       : 27/02/2017 22:13:40
LnRegistro=Evaluate(lcExp)
***************************************************
Error en el módulo : FORMSET.BUSCAR.COMMAND1.CLICK
Número de Línea No.: 5
Syntax error.
Error Número       : 10
Fecha y hora       : 27/02/2017 22:13:53
go lnRegistro
***************************************************
Lo raro es que si realizo de nuevo la busqueda puedo ir al otro resultado, lo que no me deja es llevar uno detras de otro sino que tengo que hacer la busqueda selecciono y llevo el registro, hago de nuevo la busqueda selecciono y llevo el registro. Si llevo el registro y despues selecciono el otro y llevo el registro me da el error de arriba. Lo raro es que me dice que el valor EXP_  lo toma como variable cuando es una valor.

Lionel Kieffer

unread,
Feb 28, 2017, 4:08:43 AM2/28/17
to Comunidad de Visual Foxpro en Español
La solución era muy fácil no habia problema en el código sino que faltaba algo y era que como se ve aca la variable toma el numero de registro, se selecciona la tabla y va al registro que dice la variable. Hasta ahi funciona perfecto.
LOCAL lcExp, LnRegistro
lcExp
="Exp_"+ltrim(str(fcount( "cur_grid" ) ) )
LnRegistro=Evaluate(lcExp)
select datos
go lnRegistro
Thisformset.frm_sis_afis.refresh
RELEASE lcExp
, LnRegistro

El problema era que al apretar de nuevo el botón sobre otro registro que nos da la búsqueda, como quedo el select en datos, da el error en la variable ya que no estamos trabajando con el cursor sino con la tabla, se soluciona realizando un select al cursor inicial, de esta forma
LOCAL lcExp, LnRegistro
Select cur_grid

Lionel Kieffer

unread,
Feb 28, 2017, 5:47:11 PM2/28/17
to Comunidad de Visual Foxpro en Español
Así quedaría el código finalizado para realizar consulta en tabla llevarla a cursor filtrado y despues poder llevar el registro seleccionado a la tabla de origen, le agregue esto por si en la busqueda no encuentra y genera el cursor sin registros.

Busqueda filtrada en cursor:

SELECT *, RECNO() FROM TABLA DE ORIGEN WHERE campo=consulta ORDER BY ingreso INTO CURSOR CURSOR readwrite



Acción para llevar la localización del registro a tabla
LOCAL lcExp, LnRegistro
IF eof
("CURSOR") Then
MESSAGEBOX
("No hay registros visibles","Registros",64,1)
ELSE
SELECT
CURSOR
lcExp
="Exp_"+ltrim(str(fcount( "CURSOR" ) ) )
LnRegistro=Evaluate(lcExp)
select TABLA DE ORIGEN
go
LnRegistro
Thisformset.frm_sis_afis.refresh
RELEASE lcExp
, LnRegistro
ENDIF


Si algun admin lo puede cerrar, ya que al ser el único que comenta no me aparece para finalizar el tema.

Fidel Charny

unread,
Mar 1, 2017, 7:06:44 AM3/1/17
to Comunidad de Visual Foxpro en Español
Hola Lionel
Parece que esa publicación tiene bastante tiempo (y alguna ignorancia de mi parte).
Puedes simplificar de la siguiente forma:
SELECT *, RECNO() as tb_record, .f. as tb_del FROM TABLA DE ORIGEN WHERE campo=consulta ORDER BY ingreso INTO CURSOR CURSOR readwrite

Con esto el tema se simplifica porque ya no tienes que hacer averiguaciones sobre el nombre de campo, que incluso pueden ser incorrectas:
lnRegistro = Evaluate(Thisform.Grid1.RecordSource+".tb_record")
tb_del es un campo lógico que se puede utilizar para marcar que el registro fué borrado.

La única precaución, es que en el caso de borrar un registro, el protocolo sería el siguiente:
Select (thisform.grid1.RecordSource)
REPLACE tb_del WITH .T.
DELETE         && solamente para que no se vea en el grid
Thisform.GRid1.Refresh

En el código de resolución, puedes hacer un SCAN.
Nota que es necesario mostrar los registros marcados para borrar, por lo que al inicio del proc. va SET DELETED OFF.
Nota también que este código está totalmente limitado al trabajo con tablas DBF.

PROCEDURE Actualizar_Origen
*!*---------------------------
*!*    tcTabla = "Tabla_Origen"
*!*    tcCursor = thisform.Grid1.RecordSource
*!*---------------------------
LPARAMETERS tcCursor
,tcTabla
TRY
    LOCAL lnGo
,loex as Exception
       
    LOCAL ARRAY laDatos
(1)

    SET DELETED OFF
    lnGo
= 0
    SELECT
(m.tcCursor)
    SCAN
        SCATTER TO laDatos
        lnGo
= tb_record
        DO CASE
            CASE EMPTY
(tb_Record)
                IF NOT tb_Del
                   
* Se agregó un registro al cursor
                   
* Debe agregarse un registro a la tabla
                    INSERT INTO
(m.tcTabla) FROM ARRAY laDatos
                ENDIF
               
* Si tb_Del = .T., quiere decir que se agregó un registro
               
* al cursor, pero luego se lo eliminó
               
            CASE
!EMPTY(tb_Record)    && acá se puede simplificar, pero lo dejo abierto para mayor claridad.
                SELECT
(m.tcTabla)
                GO m
.lnGo            
                IF tb_Del
                   
* Borrar el registro en Tabla original

                    IF RLOCK
()
                        GATHER FROM laDatos
                        UNLOCK
                    ENDIF
                ELSE
                   
* Modificar el registro en Tabla Original
                    IF RLOCK
()
                        DELETE
                        UNLOCK
                    ENDIF
                ENDIF
        ENDCASE
       
    ENDSCAN      
&& recuerda que ENDSCAN apunta al cursor del SCAN, por lo que no es necesario un SELECT (tcCursor)
CATCH TO loex
    loex
.UserValue = PROGRAM()
   
* ShowError(Loex)
FINALLY
    SET DELETED ON
ENDTRY



Lionel Kieffer

unread,
Mar 1, 2017, 7:04:47 PM3/1/17
to Comunidad de Visual Foxpro en Español
Muchas gracias Fidel Charny, si no me avive de ponerle el nombre al recno(), pero al trabajar con set delected on y generar el cursor de la consulta no estaría obviando los registros a ser eliminados? en la posición no cambiaría, lo que si es que no me los mostraría a los registros a eliminar. Disculpa mi ignorancia, ya que no me dedico a esto sino que lo hago como hobby; si trabajo con dbf por desconocer el tema de instalar y trabajar con motores de base de datos.

Fidel Charny

unread,
Mar 2, 2017, 6:51:40 AM3/2/17
to Comunidad de Visual Foxpro en Español
Hola Lionel
Fijate que SET DELETED OFF aparece solamente para actualizar la tabla de origen y el proc. termina con SET DELETED ON.
Esto tiene por sentido, que los registros del cursor de actualización marcados para borrar no queden ocultos para el proceso, porque pueden significar dos cosas:
1) Si el número de registro es cero y el campo tb_del = .T. no se hace nada en la tabla de origen
2) Si tb_record > 0 y tb_del = .t., significa que el procedimiento debe poner la marca de borrado en la tabla original.
Por eso es importante que el procedimiento de borrado, ponga tb_del = .T. con independencia del DELETE sobre el registro.

Si en el tratamiento del cursor de actualización pones DELETE para un registro pero no REPLACE tb_Del WITH .T., al enviar la actualización se producirá una modificación del registro original si tb_record > 0 o se agregará un registro a la tabla original si tb_record = 0.
Dicho de otra forma, el campo tb_record no debe ser modificado. Al agregarle un registro al cursor de actualización, automáticamente el registro contendrá: tb_record = 0 y tb_del = .F.

Fijate que el SET DELETED ON se repondrá aunque se produzca un error porque está colocado en la sección FINALLY del TRY / ENDTRY.

Por último, si tu idea es pasar a trabajar con base de datos, mejor olvídate de este procedimiento, porque solo presta utilidad para DBF.

Lionel Kieffer

unread,
Mar 2, 2017, 3:23:42 PM3/2/17
to Comunidad de Visual Foxpro en Español
Muchas gracias por tu tiempo, dedicación y explicación Fidel Charny. Me quedó todo muy claro.
Reply all
Reply to author
Forward
0 new messages