Ir al contenido


Foto

Operar celdas de stringgrid matematicamente


  • Por favor identifícate para responder
23 respuestas en este tema

#1 giulichajari

giulichajari

    Advanced Member

  • Miembros
  • PipPipPip
  • 477 mensajes

Escrito 27 julio 2014 - 07:09

Mi problema es que tengo en un form (Hacer ticket) un boton de agregar producto que lleva a otro form entonces se introduce cantidad y se selecciona el producto. Con estos datos se llena el stringgrid de el form hacer ticket, pero necesito hacer: precio unitario x cantidad, y sumar todos los totales de cada producto para obtener el total del ticket.

Probe con esto(en el boton agregar del form agregar producto):



delphi
  1. procedure TForm4.Button1Click(Sender: TObject);
  2. var
  3. total:Double;
  4. preciou:Double;
  5. s:integer;
  6. suma:Double;
  7. begin
  8.   if (GrillaProd.SelectedRows.Count=1) then
  9.     begin
  10.       ShowMessage('seleccione al menos un producto');
  11.     end
  12.     else
  13.       if (Edit2.Text='') then
  14.           begin
  15.             ShowMessage('Especifique la cantidad a vender');
  16.           end
  17.  
  18.       else
  19.     begin
  20.  
  21.  
  22.       with Form3.Grillaticket do
  23.         begin
  24.  
  25.           RowCount:=RowCount + 1;
  26.           Row:=RowCount - 1;
  27.           Cells[0,Row]:=queryprod.FieldByName('idproducto').AsString;
  28.           Cells[1,Row]:=Edit2.Text;
  29.           Cells[2,Row]:=queryprod.FieldByName('nombre').AsString;
  30.           Cells[3,Row]:=queryprod.FieldByName('preciou').AsString;
  31.           preciou:=StrToFloatDef(Cells[3,Row],0);
  32.           total:=preciou * StrToFloatDef(Edit1.Text,0);
  33.           Cells[4,Row]:=FloatToStr(total);
  34.  
  35.         end;
  36.           for s:=0 to Form3.Grillaticket.RowCount - 1 do
  37.         begin
  38.           suma:=suma + StrToFloatDef(Form3.Grillaticket.Cells[4,Form3.Grillaticket.Row],0)
  39.         end;
  40.       Form3.StringGrid1.Cells[1,2]:=FloatToStr(suma);
  41.     end;
  42. end;



Desde ya muchas gracias...
  • 0

#2 Sergio

Sergio

    Advanced Member

  • Moderadores
  • PipPipPip
  • 1.092 mensajes
  • LocationMurcia, España

Escrito 27 julio 2014 - 12:06

Solo dices que probaste con eso... no comentas si funcionó ni preguntas nada!  :|
  • 0

#3 giulichajari

giulichajari

    Advanced Member

  • Miembros
  • PipPipPip
  • 477 mensajes

Escrito 27 julio 2014 - 01:00

Solo dices que probaste con eso... no comentas si funcionó ni preguntas nada!  :|

Pues me quedan los totales en cero, y la suma de los totales abajo dice 1.41 y un monton de digitos. La verdad no se porque
  • 0

#4 cram

cram

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 832 mensajes
  • LocationMisiones, Argentina

Escrito 28 julio 2014 - 01:20

Te recomiendo hacer ese trabajo con tablas de memoria (o locales).
Arrastrando un TClientDataSet al form,
Desde la propiedad FieldDefs, vas creando cada campo de acuerdo con lo necesario.
Luego cuando lo tienes listos puedes crear el DataSet desde el menú contextual del icono del TDataSet, esto crea un DataSet que permanece siempre abierto (al cual lo puedes asignar un archivo externo).
Lo bueno de esta técnica es que puedes comprobar duplicados, hacer consultas (usar SQL), etc.
El uso de TDataSource y TDBGrid es idéntico que con tablas comunes.

Desde el menú contextual del icono del TClientDataSet puedes crear nuevos campos (New Field... no Add Fields...), en este caso deberías crear del tipo TAggegate, que hará el trabajo de sumar los totales.
Para el caso de los subtotales, podrás ver que existen otros campos al que se les puede dar la capacidad de multiplicar el valor de las celdas automáticamente.

Es muy largo para explicarlo y me cuesta hacerme entender, pero el resto puedes aprenderlo. En la red hay mucho material sobre esto.
Además una vez que empieces a crear los objetos, la interfaz te guiará.
Disculpa, pero es todo un tutorial el que debería hacer y no puedo en este momento.

Lo vengo usando con mucho éxito, pero el uso de TStringGrids, que supongo servirá, no creo muy llevadero. Te recomiendo cambiar de rumbo.

Saludos.

  • 0

#5 giulichajari

giulichajari

    Advanced Member

  • Miembros
  • PipPipPip
  • 477 mensajes

Escrito 28 julio 2014 - 04:56

Te recomiendo hacer ese trabajo con tablas de memoria (o locales).
Arrastrando un TClientDataSet al form,
Desde la propiedad FieldDefs, vas creando cada campo de acuerdo con lo necesario.
Luego cuando lo tienes listos puedes crear el DataSet desde el menú contextual del icono del TDataSet, esto crea un DataSet que permanece siempre abierto (al cual lo puedes asignar un archivo externo).
Lo bueno de esta técnica es que puedes comprobar duplicados, hacer consultas (usar SQL), etc.
El uso de TDataSource y TDBGrid es idéntico que con tablas comunes.

Desde el menú contextual del icono del TClientDataSet puedes crear nuevos campos (New Field... no Add Fields...), en este caso deberías crear del tipo TAggegate, que hará el trabajo de sumar los totales.
Para el caso de los subtotales, podrás ver que existen otros campos al que se les puede dar la capacidad de multiplicar el valor de las celdas automáticamente.

Es muy largo para explicarlo y me cuesta hacerme entender, pero el resto puedes aprenderlo. En la red hay mucho material sobre esto.
Además una vez que empieces a crear los objetos, la interfaz te guiará.
Disculpa, pero es todo un tutorial el que debería hacer y no puedo en este momento.

Lo vengo usando con mucho éxito, pero el uso de TStringGrids, que supongo servirá, no creo muy llevadero. Te recomiendo cambiar de rumbo.

Saludos.


Muchas gracias.. se puede asociar un dataset a un stringgrid? y el dataset tiene que ser un table?
  • 0

#6 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 28 julio 2014 - 05:15

Muchas gracias.. se puede asociar un dataset a un stringgrid? y el dataset tiene que ser un table?

No. Solamente a un DBGrid y al resto de los componentes de la misma pestaña (DB). El DataSet puede ser un Table, un Query, StoredProc... cualquier tipo de DataSet será válido.

Saludos,
  • 0

#7 giulichajari

giulichajari

    Advanced Member

  • Miembros
  • PipPipPip
  • 477 mensajes

Escrito 28 julio 2014 - 08:01

Ok lo estoy probando, el unico problema es la cantidad del articulo que no puedo venir de ningun dataset porque la establece el usuario, me dice Field not found cantidad; entonces no reconoce el cubtotal tampoco
  • 0

#8 cram

cram

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 832 mensajes
  • LocationMisiones, Argentina

Escrito 29 julio 2014 - 12:44

Ok lo estoy probando, el unico problema es la cantidad del articulo que no puedo venir de ningun dataset porque la establece el usuario, me dice Field not found cantidad; entonces no reconoce el cubtotal tampoco


Eso puedes manejarlo en el mismo DBGrid, permitiendo la modificación del campo, o bien desde un control como un TDBEdit. Lo importante es que ese campo debe estar definido en la tabla.
Lo que puede llegar a complicarte y debes presta r mucha atención es en tener activos los campos aggregate, definir correctamente las operaciones matemáticas, etc. Todo es visible desde el visor de las propiedades del objeto.

Saludos
  • 0

#9 giulichajari

giulichajari

    Advanced Member

  • Miembros
  • PipPipPip
  • 477 mensajes

Escrito 29 julio 2014 - 01:13

Leyendo en Internet y algunos manuales encontre que con boton derecho sobre el clientdataset en Fields Editor puedo agregar un campo, que puede ser aggregate lookup dat etc...

Entonces en el editor de columnas del dbgrid apareceran todos estos campos.
Tambien puede ser agregado en tiempo de ejecucion.



delphi
  1. procedure TForm4.Button1Click(Sender: TObject);
  2. var
  3. total:Double;
  4. preciou:Double;
  5. s:integer;
  6. suma:Double;
  7. begin
  8.   if (GrillaProd.SelectedRows.Count=1) then
  9.     begin
  10.       ShowMessage('seleccione al menos un producto');
  11.     end
  12.     else
  13.       if (Edit2.Text='') then
  14.           begin
  15.             ShowMessage('Especifique la cantidad a vender');
  16.           end
  17.  
  18.       else
  19.     begin
  20.         with Form3.ClientDataSet1 do
  21.           begin
  22.  
  23.             Insert;
  24.             FieldByName('cant').AsFloat:=StrToFloat(Edit2.Text);
  25.             FieldByName('idproducto').AsInteger:=GrillaProd.DataSource.DataSet['idproducto'];
  26.             FieldByName('preciou').AsFloat:=queryprod.FieldByName('preciou').AsFloat;
  27.             FieldByName('total').AsFloat:=((StrToFloat(Edit2.Text)) * (queryprod.FieldByName('preciou').AsFloat));
  28.             if State in [dsEdit,dsInsert] then
  29.               Post;
  30.             if ChangeCount>0 then
  31.               begin
  32.                 ApplyUpdates(0);
  33.  
  34.  
  35.               end;
  36.  
  37.  
  38.  
  39.         end;
  40.       end;
  41. end;



En el codigo de arriba no da errores, lo unico que no me aparece es el total, hice el edit por precio unitario pero no pasa nada...jaja otro problema distinto pero muchas gracias
  • 0

#10 cram

cram

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 832 mensajes
  • LocationMisiones, Argentina

Escrito 29 julio 2014 - 02:10

Leyendo en Internet y algunos manuales encontre que con boton derecho sobre el clientdataset en Fields Editor puedo agregar un campo, que puede ser aggregate lookup dat etc...

Entonces en el editor de columnas del dbgrid apareceran todos estos campos.
Tambien puede ser agregado en tiempo de ejecucion.


Es precisamente eso: lo del clic secundario, lo que te había sugerido en un principio  (li). Pero también te sugerí no asociarlo a alguna tabla de la base de datos, sino crearlo como tabla de memoria. Pues, haciendo uso de EmptyDataSet puedes reiniciar esa lista fácilmente.
Supongo que casi todo es posible hacerlo en tiempo de ejecución. Aunque te recomiendo que primero lo hagas funcionar "por el lado más sencillo".

Cuando termines de agregar esos campos con el menú contextual (clic secundario) verás las propiedades, presta atención a estas:
- Active
- DefaultExpression
- Currency
- DisplayFormat
- DisplayLabel
- Expression
- FieldKind (automáticamente se poe a fkAggregate)
- FieldName

Por ejemplo una expresión para Expression, puede ser:



delphi
  1. sum(Precio * Cantidad)



Aclaración:
Los campos lookup te sirven para agregar detalles, haciendo uso de claves foráneas.
Los campos aggregate, son los que deberías usar para obtener los totales.

  • 0

#11 giulichajari

giulichajari

    Advanced Member

  • Miembros
  • PipPipPip
  • 477 mensajes

Escrito 01 agosto 2014 - 01:22

Bueno ya logre acomodar la grilla de ticket y lo que te pedia pero ahora al cerrar la aplicacion desde la cruz dice:
Project1.exe ha detectado un problema y debe cerrarse

Yo siempre voy guardando una copia del proyecto a medida que lo voy haciendo. Entonces agarre la copia y volvi a poner el DataSet y todo lo que me recomendaste y vuelve el problema.

Gracias igual Saludos

Y al cerrar la IDE de delphi xe2 me sale el error de midas.dll acces violation, no se si tu has tenido este problemas y me podrias decir como lo resolviste.
Ya probe poner en el uses midasLib y en windows/system32 ya tengo esa libreria. Porque estuve leyendo en los foros sobre este error.
  • 0

#12 cram

cram

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 832 mensajes
  • LocationMisiones, Argentina

Escrito 01 agosto 2014 - 12:47

En algún lugar de DelphiAccess se habla sobre donde poner a MIDAS.DLL.
Lo más simple es ponerlo en el lugar del ejecutable, al menos es lo que leí, es el primer lugar en que el programa lo busca.
Podría ser la versión de MIDAS.

No soy un experto en el tema, pero en tu lugar buscaría el MIDAS.DLL que existe en el directorio de instalación de Delphi, dentro del subdirectorio redist, allí hay un archivo MIDAS.DLL (uno para la versión de 32 bits y otro para la versión de 64 bits) y lo colocaría en el directorio de salida del ejecutable.

Saludos
  • 0

#13 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14.448 mensajes
  • LocationMéxico

Escrito 01 agosto 2014 - 01:03

En algún lugar de DelphiAccess se habla sobre donde poner a MIDAS.DLL.
Lo más simple es ponerlo en el lugar del ejecutable, al menos es lo que leí, es el primer lugar en que el programa lo busca.
Podría ser la versión de MIDAS.

No soy un experto en el tema, pero en tu lugar buscaría el MIDAS.DLL que existe en el directorio de instalación de Delphi, dentro del subdirectorio redist, allí hay un archivo MIDAS.DLL (uno para la versión de 32 bits y otro para la versión de 64 bits) y lo colocaría en el directorio de salida del ejecutable.

Saludos


Otra opción es agregar en el uses midaslib y ya no requerirás de la librería MIDAS.DLL

Saludos
  • 0

#14 giulichajari

giulichajari

    Advanced Member

  • Miembros
  • PipPipPip
  • 477 mensajes

Escrito 01 agosto 2014 - 04:33

Muchas gracias ya lo solucione.
  • 0

#15 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14.448 mensajes
  • LocationMéxico

Escrito 02 agosto 2014 - 10:36

Muchas gracias ya lo solucione.


¿Podrías compartirnos cual fue la solución? De esa forma si alguien tiene el mismo problema, éste hilo será de gran ayuda.

Saludos
  • 0

#16 giulichajari

giulichajari

    Advanced Member

  • Miembros
  • PipPipPip
  • 477 mensajes

Escrito 02 agosto 2014 - 11:21

Si disculpa..
En el Project Manager donde estan las units del proyecto click derecho,sobre "nombre de proyecto.exe", view source (esto mostrara el codigo fuente)  y en "includes" incluir "MidasLib", el error a mi me lo seguia dando porque habia incluido midaslib pero en una unit del proyecto y no en el .exe.

Saludos  :smiley:
  • 0

#17 giulichajari

giulichajari

    Advanced Member

  • Miembros
  • PipPipPip
  • 477 mensajes

Escrito 04 agosto 2014 - 12:56

Lo que no entiendo ahora es como aplicar los cambios(cosa que no me explicaste jaja :tongue:)

Ahora tengo(para cargar PRODUCTOS):



delphi
  1. Form3.ZQuery1.ParamByName('idp').AsInteger:=GrillaProd.DataSource.DataSet.FieldByName('idproducto').AsInteger;
  2.         with Form3.ClientDataSet1 do
  3.           begin
  4.             Open;
  5.           Insert;
  6.             FieldByName('cantidad').AsFloat:=StrToFloat(Edit3.Text);
  7.             FieldByName('nombre').AsString:=ZQuery1.FieldByName('nombre').AsString;
  8.  
  9.             FieldByName('preciou').AsFloat:=ZQuery1.FieldByName('preciou').AsFloat;
  10.             FieldByName('total').AsFloat:=((StrToFloat(Edit3.Text)) * (ZQuery1.FieldByName('preciou').AsFloat));
  11.  
  12.           if State in [dsEdit,dsInsert] then
  13.               Post;
  14.             if ChangeCount>0 then
  15.               begin
  16.                 ApplyUpdates(0);
  17.  
  18.               end;
  19.  
  20.         end;



Pero lo que necesito es.
insertar un ticket
insertar en otra tabla los productos que le pertenecen(tabla de relacion)
insertar el cliente(idcliente) que hizo la compra asociado a idticket,
insertar la sucursal(idsucursal) donde se registra la venta asociada al ticket,

Pero una cosa es el query que alimenta al datasetprovider para llenar la grilla, y otra cosa es lo que voy a hacer ocn los datos una vez llena la grilla.
  • 0

#18 cram

cram

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 832 mensajes
  • LocationMisiones, Argentina

Escrito 04 agosto 2014 - 01:56

No entiendo mucho pero, lo que haría para el caso de una boleta (ticket) es lo siguiente:

1. Obtendría los datos referentes a la cabecera
2. Tomaría los datos del cuerpo del ticket del ClientDataSet
3. Otros datos los tomaría de sus respectivas tablas, no sé cuáles serían, depende.

Imprimiría la boleta enviando los datos en el orden correspondiente tomando los datos de diferentes datasets, pero la venta guardaría con otra estructura, en la que más se vé como una factura, donde hay una cabecera y detalle (en el detalle iría el listado de artículos con sus respectivas cantidades, y subtotales).

Pero nadie pudo haberte explicado, pues no es el tema original y habría que ser adivino.

Por otra parte, según tengo entendido, ApplyUpdates aplica los cambios del ClientDataSet a la tabla de la base de datos a la cual
está asociado.

Saludos

  • 0

#19 giulichajari

giulichajari

    Advanced Member

  • Miembros
  • PipPipPip
  • 477 mensajes

Escrito 04 agosto 2014 - 02:49

No entiendo mucho pero, lo que haría para el caso de una boleta (ticket) es lo siguiente:

1. Obtendría los datos referentes a la cabecera
2. Tomaría los datos del cuerpo del ticket del ClientDataSet
3. Otros datos los tomaría de sus respectivas tablas, no sé cuáles serían, depende.

Imprimiría la boleta enviando los datos en el orden correspondiente tomando los datos de diferentes datasets, pero la venta guardaría con otra estructura, en la que más se vé como una factura, donde hay una cabecera y detalle (en el detalle iría el listado de artículos con sus respectivas cantidades, y subtotales).

Pero nadie pudo haberte explicado, pues no es el tema original y habría que ser adivino.

Por otra parte, según tengo entendido, ApplyUpdates aplica los cambios del ClientDataSet a la tabla de la base de datos a la cual
está asociado.

Saludos


Exacto, los 3 puntos que explicas de obtener datos los entiendo pero donde coloco el insert por ejemplo, de el ticket y su cabecera?
Tengo los productos en la grilla con el dataset y debo insertar sus id y el id de ticket para conocer cada compra.
Osea en este momento el grid funciona junto con el dataset como vos me enseñaste, pero debo vaciar esa tabla cada vez que se quiera hacer un ticket, y al vaciarla insertar donde corresponda.
Creo haberme explicado...
  • 0

#20 cram

cram

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 832 mensajes
  • LocationMisiones, Argentina

Escrito 04 agosto 2014 - 03:57

Es que deberás tener una  estructura de fondo que se acomode a ese modelo:

Una tabla de venta y una de detalle, por otra parte una de artículo de donde tomar sus datos, luego reunir esto haciendo que el detalle se incorpore a ese ClientDataSet y los datos de la venta correspondan a la cabecera.
Es decir que será una tabla de venta que se corresponde con los datos de la cabecera de la boleta y por otro lado los de detalles de artículos de la venta que se corresponden con el detalle de la venta (artículo, cantidad, subtotal) que generan un subtotal (o total directamente según el caso) general.
Ese insert que dices se da una vez por cada venta y los inserts del clientdataset se dan una vez por cada artículo ingresado a la lista.
Esto tiene mucho que ver con el comportamiento y el modelo que le das a esa venta y es en algo que yo al menos no puedo ayudarte, pues se trata de lógica del comercio (o de tu propia aplicación, como quieras llamarlo).

Mi forma de ver las cosas:
Por una parte tengo una tabla de venta que es en la que se guardan los datos de cabecera, donde tengo campos como el número de serie de la factura, el día, la hora, la referencia al cliente, el total general (o valor total), el número de punto de venta, etc.
Por otra parte, otra tabla donde cada línea de detalle de venta se corresponde con un detalle de la venta que se ve en la boleta (o factura) y hace referencia a la correspondiente fila de la tabla de venta. En cada fila de esta tabla, figura también la referencia a un artículo en particular, la cantidad y el precio unitario (no el subtotal, pues debe estar normalizada y sí el precio total pues este varía con el tiempo).
Por otra parte la tabla de artículos de la cual tomo los datos, la tabla de clientes de la cual tomo los datos del cliente, las de sucursal, parámetros (de donde obtengo los datos del comercio), etc.
Pero esto es mi punto de vista, y nada tiene que ver con el problema en cuestión, espero que te sirva igual.

Saludos
  • 0




IP.Board spam blocked by CleanTalk.