Problema al almacenar valor de Check ubicado dentro de un Grid en un campo

401 views
Skip to first unread message

José María Lanza

unread,
Jan 3, 2016, 10:08:53 PM1/3/16
to Comunidad de Visual Foxpro en Español
Hola soy nuevo en el tema de foros así como también en Visual FoxPro, desde ya pido disculpas si estoy cometiendo un error al hacer mi consulta creando un tema nuevo.

Tengo una base de datos con varias tablas, entre ellas la tabla productos, la cual tiene un campo llamado "eliminar", este campo lo creé para almacenar el valor 1 de un checkbox que está dentro de un grid para así poder eliminar varios registros de una sola vez mediante el botón eliminar el cual tiene el siguiente código:

IF thisform.pgfABMProductos.pgeliminar.opgEliminar.opEliminarVarios.Value = 1 // Esto hace referencia a un grupo de opciones que consta de 2 radiobutton, este sería uno de ellos.
    IF MESSAGEBOX("¿Realmente desea eliminar los registros seleccionados?", 4+32+256, "ELIMINANDO REGISTROS") = 6
       DELETE FROM productos WHERE productos.eliminar = 1
    ENDIF
ENDIF

por lo que pude comprobar (Ingresando a la tabla y colocando el valor 1 al campo eliminar) anda perfectamente.

Sin más vueltas esta es la situación:
Al marcar el checkbox de cualquier registro del grid este almacena el valor, pero en el último registro de la tabla!!!
El código que escrbí en el evento Interectivechange es el siguiente:

REPLACE eliminar WITH this.Value

Al principio lo hice en el evento click pero es el mismo resultado, este es el código del evento click:

SELECT productos
IF productos.idproducto = prod.idproducto
IF thisform.dgvProductos.clmneliminar.chkeliminar.Value = 0
DO WHILE productos.idproducto=prod.idproducto
REPLACE productos.eliminar WITH 1
ENDDO
ELSE
IF thisform.dgvProductos.clmneliminar.chkeliminar.Value = 1
DO WHILE productos.idproducto=prod.idproducto
REPLACE productos.eliminar WITH 0
ENDDO
        ENDIF
       ENDIF
ENDIF

Ayuda por favor!!! ya no se que hacer!!! y pido disculpas nuevamente si cometí algún error al publicar esto

Fidel Charny

unread,
Jan 4, 2016, 7:51:06 AM1/4/16
to Comunidad de Visual Foxpro en Español
Entiendo que en el checkbox del grid no necesitas poner ningún código.
Lo que si es imprescindible es que en la configuración del control grid, tengas liado el ControlSource de la columna en la que está el checkbox al campo de la tabla:
Supongamos que el checkbox está en la columna 4 del Control Grid y que el control grid se llama "Grid1".
Thisform.Grid1.Column4.ControlSource = "productos.eliminar"
La columna del checkbox debe estar configurada como Sparse=.F. y Readonly= .F. y el control Grid debe ser AllowCellSelection = .T.
Para que el resultado de la acción del botón del optiongroup sea visible, debes tener configurado SET DELETED ON y siempre conviene, luego de marcar registros para borrar, hacer un refresh del control grid.

DELETE FROM productos WHERE productos.eliminar = 1
Thisform.Grid1.REfresh

Una cuestión distinta es si los registros de una tabla de productos deben o no eliminarse. Normalmente conviene tener un campo en la taba que indique producto desactivado o algo por el estilo, para impedir que se efectuen ciertas operaciones con determinado registro. Si borras los registros de la tabla de productos, perderás la referencia de los productos borrados cuyo identificador se incluyo en operaciones de compra, venta o movimiento de stock.

Jairo Miranda

unread,
Jan 4, 2016, 2:00:25 PM1/4/16
to publicesvfoxpro
*si  la idea es  
*puedes colocarlo en el Valid 
if thisform.Grid1.Column1.Check1.value   && dado que sea logico 
   replace borrado with "OK"
else
  repalce borrado with " "
endif 

JM 



José María Lanza

unread,
Jan 4, 2016, 7:52:29 PM1/4/16
to Comunidad de Visual Foxpro en Español
Hola Fidel, gracias por contestar en efecto las propiedades que mencionaste antes las tengo a todas configuradas de la manera que dices así como el SET DELETED ON, en cuanto a lo de hacer un refresh del grid tienes razón, ya lo he echo y gracias por hacerme ver lo de las referencias del producto, genial tu consejo, lo voy a implementar.

Hay algo que olvidé mencionar... y es que el control source del grid es una consulta SQL, el código es el siguiente:

SELECT idproducto, eliminar, producto, categorias.categoria, precio_compra, precio_venta, stock FROM productos INNER JOIN categorias ON categorias.idcategoria = productos.idcategoria INTO CURSOR prod READWRITE ORDER BY producto

Pienso que quizás el hecho de haber creado un cursor es la causa que al momento de querer guardar el valor del check en la tabla éste se almacenaba (y digo almacenaba porque ahora se almacena en el primero!!) en el último registro?

José María Lanza

unread,
Jan 4, 2016, 7:57:08 PM1/4/16
to Comunidad de Visual Foxpro en Español
Hola Jairo gracias a ti también por contestar, el campo de mi tabla no es lógico, es numérico, pero ya probé lo que me dijiste y el resultado sigue siendo el mismo. Gracias por tu ayuda

Jose Mario

unread,
Jan 5, 2016, 8:19:17 AM1/5/16
to Comunidad de Visual Foxpro en Español
no te compliques yo lo que hago es utilizar un campo texto del grid, sin insertar nada
y le coloco eliminar "S", elimnar ="N"

todo lo que tiene S lo elimino, 

sin tanta vuelta

Jairo Miranda

unread,
Jan 5, 2016, 8:47:15 AM1/5/16
to publicesvfoxpro

No es por contradecirte Jose Mario pero a los clientes les gusta es solo dar clic , seleccionar de un combo de una lista, incrementar  en un spinner o escoger en un option  y que el sistema haga el resto... , para mi la consulta podria ser :

SELECT idproducto, .f. as eliminar, producto, categorias.categoria, precio_compra, precio_venta, stock FROM productos INNER JOIN categorias ON categorias.idcategoria = productos.idcategoria INTO CURSOR prod READWRITE ORDER BY producto


una vez terminado de dar clic en los checks en el botón guardar .

Select   idproducto from prod where eliminar = .t. into cursor tCursor

select tCursor
scan 
      delete from productos where idproducto = tCursor.idproducto
endscan 

JM 

Fidel Charny

unread,
Jan 5, 2016, 9:48:48 AM1/5/16
to Comunidad de Visual Foxpro en Español
José María:
De acuerdo a lo que planteas, tendrás que ponerte de acuerdo.
Esto no puede funcionar como esperas:  DELETE FROM productos WHERE productos.eliminar = 1, porque la marca de eliminación (eliminar=1) la estás poniendo en un cursor llamado "prod" y no mencionas en ninguna parte cómo se relaciona la tabla con el cursor. Supuestamente deberías utilizar el idproducto como relación.

Para simplificar, pongo solamente dos campos en el control grid, suponiendo que la columna 2 tiene un checkbox como currentcontrol.
With thisform
        .Grid1.ColumnCount = 2
        .Grid1.RecordSource = "PROD"
        .Grid1.Column1.ControlSource="Prod.idproducto"
        .Grid1.Column2.ControlSource="Prod.Elilminar"
        .Grid1.Column2.Readonly  = .F.
endwith
Si las marcas de borrado (Eliminar = 1) se producen en el cursor "Prod", tendrías que intentar con algo como esto:
DELETE productos FROM Prod WHERE Productos.idProducto = Prod.idProducto AND Prod.Eliminar = 1

En cuanto a la conservación del valor del campo eliminar en la tabla Productos, no le veo ningún sentido. Ni siquiera debería existir ese campo en la tabla, salvo que lo reserves para otros usos. El campo "eliminar" debería agregarse al Select ( por ejemplo, 0 as eliminar ).
Dicho sea de paso, para cualquier situación de filtrado será mucho más rápido un campo lógico si se trata de una cuestión binaria.

José María Lanza

unread,
Jan 5, 2016, 10:32:44 PM1/5/16
to Comunidad de Visual Foxpro en Español
Gracias Fidel al final lo pude solucionar, en efecto es lo que decías y lo que yo también pensaba, el cursor me estaba complicando más las cosas, por lo que al final usé un locate for y un set filter. así almacena sin ningún problema el valor de mi checkbox sin tener que partirme el coco para conseguirlo jaja, gracias a todos por su ayuda! :D.

Pero ahora tengo otro problema :'( quiero seleccionar una fila del grid haciendo click en cualquier parte del registro  y que los valores de esta aparezcan en varios textbox para poder modificarlos. Peeeero no logro dar con esta solución, ya que por ejemplo al hacer click en una fila, supongamos en el campo producto el txtproducto se llena con el valor, pero los demás textbox (txtprecio_compra, txtprecio_venta, spncantidad y txtidproducto(de solo lectura)) no lo hacen, al igual que al hacer click en el campo idproducto, el txtidproducto se llena con ese valor, pero los demás no, y hasta el punto que tengo un id de un producto y el nombre de otro el el txtproducto. Gracias de nuevo por su ayuda! :D 

José María Lanza

unread,
Jan 5, 2016, 10:35:30 PM1/5/16
to Comunidad de Visual Foxpro en Español
este es el código que tengo en el evento click del grid (también lo probé en el evento AfterRowColChange):

thisform.pgfABMProductos.pgModificar.txtIdProducto.Value = this.clmnIdProducto.Text1.Value
thisform.pgfABMProductos.pgModificar.txtProducto.Value = this.clmnProducto.Text1.Value
thisform.pgfABMProductos.pgModificar.cmbCategoria.Value = this.clmnCategoria.Text1.Value
thisform.pgfABMProductos.pgModificar.txtPrecio_Compra.Value = this.clmnPrecio_Compra.Text1.Value
thisform.pgfABMProductos.pgModificar.txtPrecio_Venta.Value = this.clmnPrecio_Venta.Text1.Value
thisform.pgfABMProductos.pgModificar.spnCantidad.Value = this.clmnStock.Text1.Value

Fidel Charny

unread,
Jan 6, 2016, 7:08:47 AM1/6/16
to Comunidad de Visual Foxpro en Español
José María:
Debes tener presente que un control grid es un Browse sofisticado, por lo siempre debes utilizar los campos del cursor de la propiedad recordsource del grid.
Por ejemplo, utilizando ControlSource y Refresh
[Init del Form (o un método del form llamado desde el Init)]
* 1 Configuración del control Grid (Asignación de REcordSource, ControlSource de los Columns, etc)

* 2 Configuración de los elementos de la interfaz
lcCursor
= Thisform.grdObject.RecordSource
WITH thisform
.pgfABMProductos.pgModificar
   
.txtIdProducto.ControlSource=lcCursor+".IdProducto"
   
.txtProducto.ControlSource = lcCursor+".Producto"
   
.CmbCategoria.ControlSource = lcCursor+".Categoria"

*   etc
ENDWITH
* Acá escribo una forma más general pero, por ejemplo, si sé que el cursor se llama "Pepa", puedo escribir directamente:
with thisform.pgfABMProductos.pgModificar
       
.txtIdProducto.ControlSource = "Pepa.IdProducto"
       
.txtProducto.ControlSource = 'Pepa.Producto'
       
.cmbCategoria.ControlSource = [Pepa.Categoria]
endwith



[Grid.AfterRowColChange]
WITH thisform
.pgfABMProductos.pgModificar
   
.txtIdProducto.refresh
   
.txtProducto.refresh
   
.CmbCategoria.refresh
ENDWITH

Llamar a cada método Refresh de cada objeto es mejor que utilizar Thisform.Refresh. En primer lugar porque se ejectua el método solamente para los objetos que lo necesitan (aquellos que están liados por ControlSource). En segundo lugar, porque para el caso del pageframe sería necesario hacer un refresh para cada objeto Page.

Al utilizar ControlSource (en el control grid corresponde a la columna [no al CurrentControl] y puede ser implícito o explícito) se pueden introducir modificaciones al cursor o tabla desde cualquier control liado por ControlSource, siempre que sea Readonly=.f. y Enabled = .f. y, que el cursor o tabla no sean de solo lectura.

Alternativamente (y muchas veces más sencillo) es utilizar la propiedad Value de los controles, teniendo presente que estos controles deberían ser REadonly = .T. o Enabled = .F., porque las modificaciones que se introduzcan ahí no se reflejarán en el cursor (ni en ningún lado), a menos que crees también un método de modificación específico.
Sin embargo, en el caso de Combobox y Listbox, si están correctamente configurados (o sea BoundColumn apunta a la columna que tiene el tipo de dato del cursor que se muestra), será necesario liarlo por ControlSource a dicho cursor para que refleje los cambios en forma natural.
*[AfterRowColChange]
lcCursor
= This.RecordSource
WITH thisform
.pgfABMProductos.pgModificar
   
.txtIdProducto.Value = EVALUATE(lcCursor+".IdProducto")
   
.txtProducto.Value =  EVALUATE(lcCursor+".Producto")
   
*!*  .CmbCategoria.Value = EVALUATE(lcCursor+".Categoria")
ENDWITH
Esto también se puede escribir del modo siguiente:
*[AfterRowColChange]
SELECT
(This.RecordSource)
WITH thisform
.pgfABMProductos.pgModificar
   
.txtIdProducto.Value= IdProducto
   
.txtProducto.Value =  Producto

ENDWITH

Mario Oviedo

unread,
Jan 6, 2016, 8:41:08 AM1/6/16
to publice...@googlegroups.com
lo que tenes que hacer es armar un formulario 
que el grid tenga su propiedad allowcellselection=.f. false
readonly=.f. false
en dobleclick   colocar llamada del metodo
thisform.modificar()
este metodo (modificar) tu lo creas

LOCAL oCustInfo as form 
DO FORM tuformulario NAME oCustInfo LINKED WITH RECNO() NOSHOW 
oCustInfo.AutoCenter = .t.
oCustInfo.show(1)  && show modaly
this.Refresh()


modificar.jpg

José María Lanza

unread,
Jan 7, 2016, 2:41:36 PM1/7/16
to Comunidad de Visual Foxpro en Español
Problemas solucionadoss!!! muchas gracias por su ayuda!!! :D gracias a sus consejos pude dar con la solución! :D :D

Quizás el código no es como lo haría un programador con experiencia pero cumple con su función.

Para el próximo que tenga el mismo problema o quiera hacer algo parecido primero explico lo que me pasaba:
Como en un principio mencioné, no podía almacenar el valor de un checkbox ubicado en el grid en la tabla debido a que los registros los guardaba en un cursor y no sabía qué código debía escribir para que hiciera esto. Para solucionar este problema decidí poner la propiedad RecordSourceType de mi grid en 0 (Tabla) para que el valor del check se almacene automáticamente en la tabla "Productos" sin necesidad de escribir un código. Pero esto me trajo un problema, y es el que mencioné luego:
 "al hacer click en una fila, supongamos en el campo producto el txtproducto se llena con el valor, pero los demás textbox no lo hacen, al igual que al hacer click en el campo idproducto, el txtidproducto se llena con ese valor, pero los demás no, y hasta el punto que tengo un id de un producto en txtidproducto y el nombre de otro en el txtproducto".
Este era el código:

WITH thisform.pgfABMProductos.pgModificar
.txtIdProducto.Value = productos.idproducto
.txtProducto.Value = productos.producto
.cmbCategoria.Value = productos.categoria
.txtPrecio_Compra.Value = productos.precio_compra
.txtPrecio_Venta.Value = productos.precio_venta
.spnCantidad.Value = productos.stock
ENDWITH

El código creo yo que no está mal en un principio pero al trabajar directamente con la tabla funcionaba de esa manera...

Por esta razón decidí volver a crear un cursor, ya que con éste al hacer click en cualquier campo del registro se llenan automáticamente todos los textbox sin ningún problema. Este es el código:

WITH thisform.pgfABMProductos.pgModificar
.txtIdProducto.Value = prods.idproducto
.txtProducto.Value = prods.producto
.cmbCategoria.Value = prods.categoria
.txtPrecio_Compra.Value = prods.precio_compra
.txtPrecio_Venta.Value = prods.precio_venta
.spnCantidad.Value = prods.stock
ENDWITH

*Como ven es el mismo código solo que en vez de sacar los datos directamente de la tabla lo hago desde el cursor...

Decidí poner manos a la obra para poder dar con la solución planteada al principio usando este cursor, Gracias a su ayuda pude lograrlo.
Este es el código:

SELECT prods
REPLACE prods.eliminar WITH this.Value
SELECT productos
REPLACE productos.eliminar WITH prods.eliminar FOR productos.idproducto = prods.idproducto
SELECT prods
thisform.dgvProductos.Refresh()

Dejo el código de mi botón Modificar también por las dudas :D

SELECT prods
REPLACE prods.producto WITH thisform.pgfABMProductos.pgModificar.txtProducto.Value
REPLACE prods.precio_compra WITH thisform.pgfABMProductos.pgModificar.txtprecio_compra.Value
REPLACE prods.precio_venta WITH thisform.pgfABMProductos.pgModificar.txtprecio_venta.Value
REPLACE prods.stock WITH thisform.pgfABMProductos.pgModificar.spncantidad.Value
SELECT productos
REPLACE producto WITH prods.producto FOR prods.idproducto = productos.idproducto
REPLACE productos.idcategoria WITH thisform.pgfABMProductos.pgModificar.cmbcategoria.ListIndex FOR prods.idproducto = productos.idproducto
REPLACE precio_compra WITH prods.precio_compra FOR prods.idproducto = productos.idproducto
REPLACE precio_venta WITH prods.precio_venta FOR prods.idproducto = productos.idproducto
REPLACE stock WITH prods.stock FOR prods.idproducto = productos.idproducto
SELECT prods
thisform.dgvProductos.Refresh()


El lunes, 4 de enero de 2016, 0:08:53 (UTC-3), José María Lanza escribió:
Reply all
Reply to author
Forward
0 new messages