Ir al contenido



Foto

Barra de progreso o similar mientras se actualiza una DB

barra de progreso

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

#1 Gaston

Gaston

    Advanced Member

  • Miembros
  • PipPipPip
  • 69 mensajes

Escrito 12 noviembre 2016 - 08:20

Hola, de seguro me está faltando algo que escapa a mis conocimientos. Quiero mostrar un contador, un mensaje o una barra de progreso mientras actualizo una tabla, el problema es que me actualiza la tabla y luego aparece el mensaje o lo que fuese que llame, es decir, no sirve. Primero probé con un formulario, como no dio resultado pensé en poner un label no visible en el form y hacerlo visible cuando se actualiza y de paso mostrar la cantidad de registros a procesar de modo que quede: Calculando Saldos, por favor espere: Registro: 1 de 200.

El label9 tiene el texto 'Calculando Saldos, por favor espere: Registro:'


delphi
  1. procedure TfrmReg.btnCalcSaldosClick(Sender: TObject);
  2. var
  3. banco:Integer;
  4. sqltxt:String;
  5. saldo:Currency;
  6. actual, ultimo:Integer;
  7. begin
  8. Label9.Visible:=true;
  9. Label10.Visible:=true;
  10. saldo:=0;
  11. sqltxt:='SELECT * FROM reg WHERE banco='+IntToStr(cmbBanco.KeyValue)+
  12. ' ORDER BY banco, fecha, id;';
  13. actual:=0;
  14. DataM.ZQSaldos.Close;
  15. DataM.ZQSaldos.SQL.Text:=sqltxt;
  16. DataM.ZQSaldos.Open;
  17. DataM.ZQSaldos.First;
  18. ultimo:=DataM.ZQSaldos.RecordCount;
  19. WHILE NOT DataM.ZQSaldos.EOF DO
  20. begin
  21. actual:=actual+1;
  22. Label10.Caption:=IntToStr(actual)+'de '+IntToStr(ultimo);
  23. saldo:=saldo+DataM.ZQSaldos.FieldByName('debitos').AsCurrency-DataM.ZQSaldos.FieldByName('creditos').AsCurrency;
  24. DataM.ZQSaldos.Edit;
  25. DataM.ZQSaldos.FieldByName('saldo').AsCurrency:=saldo;
  26. DataM.ZQSaldos.Post;
  27. DataM.ZQSaldos.Next;
  28. end;
  29. ShowMessage('Finalizado');
  30. Label9.Visible:=false;
  31. Label10.Visible:=false;
  32. DataM.ZQGridReg.Close;
  33. DataM.ZQGridReg.Open;
  34. DBGrid1.Refresh;
  35. end;

Con este código cuando se hace click en el botón Actualizar saldos el botón queda presionado, actualiza y luego hace visible los labels y un showmessage que puse ahí para probar.

Lo que pretendo es primero muestre el label9 y luego entre al while, pero no entiendo por qué no lo hace. Tema aparte es el tiempo que tarda, unos 4 segundos con apenas 50 registros, pero ese es otro tema.

 

Saludos.


  • 0

#2 Gaston

Gaston

    Advanced Member

  • Miembros
  • PipPipPip
  • 69 mensajes

Escrito 12 noviembre 2016 - 09:28

Perdón pero estuve toda la tarde con este tema sin encontrarle la vuelta, lo posteo acá y a los 15 minutos encuentro la solución, intenté eliminar el post pero creo que no se puede, entonces comento que lo que me faltaba era simplemente un


delphi
  1. Application.ProcessMessages;

Es decir quedó el while de esta forma:


delphi
  1. WHILE NOT DataM.ZQSaldos.EOF DO
  2. begin
  3. ProgressBar1.Position:=actual;
  4. Application.ProcessMessages;
  5. actual:=actual+1;
  6. Label10.Caption:=IntToStr(actual)+'de '+IntToStr(ultimo);
  7. saldo:=saldo+DataM.ZQSaldos.FieldByName('debitos').AsCurrency-DataM.ZQSaldos.FieldByName('creditos').AsCurrency;
  8. DataM.ZQSaldos.Edit;
  9. DataM.ZQSaldos.FieldByName('saldo').AsCurrency:=saldo;
  10. DataM.ZQSaldos.Post;
  11. DataM.ZQSaldos.Next;
  12. end;

Eso sí, es terriblemente lento, así que si alguien ve algo que me pueda estar ocasionando esa lentitud, me avisa.

 

Saludos. 


  • 0

#3 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 754 mensajes
  • LocationArgentina

Escrito 12 noviembre 2016 - 09:34

Es que ese codigo se ejecuta de manera secuencial. Osea, para que se entienda, se ejecuta todo de un "plumazo". Lo que vos necesitas es tener "dos bloques" de codigo ejecutandose al mismo tiempo. La forma de lograr esto es usando hilos (Threads)

 

Toda aplicacion Delphi/FreePascal, tienne un hilo principal, o main thread. A grandes rasgos y en windows (no creo que sea muy diferente en otra plataforma), es este thread el que recibe todos los mensajes del sistema operativo tales como: minimizar form, mostrar form, pintar form, ocultar form, presionar boton, etc.

 

Osea, aunque te parezca que una aplicacion no esta haciendo nada, en realidad esta haciendo mucho: constantemente dibuja todos los controles, estos tambien responden a cosas como "el mouse esta encima" (que pasa cuando pones el puntero sobre un boton? este "cambia" visualmente)

 

Ahora bien, si vos pones codigo a ejecutar para que haga algo, y este tarda, la aplicacion esta "trabada" en ese punto y no puede hacer todo lo demas. Por eso parece tildada. Ni siquiera podes moverla si queres arrastar el form, ni maximiar, minimizar, nada de nada. En realidad todo eso va quedando guardado en una cola de mensajes que maneja el sistema operativo, y despues tu aplicacion va a ir desencolando y procesando uno por uno. Osea tu aplicacion, cuando no esta haciendo "nada" o tiene "tiempo libre" saca un mensaje de esa cola y lo procesa. Eso es justamente lo que hace el Application.ProcessMessages

 

La solucion "correcta" es crear otro hilo que se dedica a realizar calculos o lo que fuera, dejando el hilo principal para que continue su trabajo. 

 

No te recomiendo para nada Application.ProcessMessages. Aca y aca tambien mas info. Respuesta corta: no lo hagas porque en muchos casos puede ocasionar problemas dificiles de encontrar en el largo plazo

 

Te di un panorama mas o menos teorico y explicado de forma "amigable" de que sucede tras los bastidores, porque ejemplos de como escribir Threads en Delphi y FPC creo que sobran. Ahora, te advierto que la programacion concurrente (en cualquiera de sus formas) es un arte, pero como todo arte, muy apasionante


  • 2

#4 Gaston

Gaston

    Advanced Member

  • Miembros
  • PipPipPip
  • 69 mensajes

Escrito 13 noviembre 2016 - 12:51

Hermoso balde de agua fría jaja 8o|

Gracias Agustín, entiendo lo me decis, me leí los links y todos coinciden con lo que vos muy bien me explicas. La solución sería crear otro hilo que ejecute la actualización de la tabla y muestre la barra de progreso, al menos es lo que entendí.

El tema es que no es algo simple de implementar y requiere tiempo de estudio y práctica. Ahora me conformaría con poder poner un cartel que diga 'Espere, procesando datos' y mientras tanto deshabilito el Form para que el usuario no pueda tocar nada. Es esto posible de implementar de manera sencilla?


  • 0

#5 apexcol

apexcol

    Newbie

  • Miembros
  • Pip
  • 1 mensajes

Escrito 08 mayo 2017 - 03:10

Prueba con información los métodos DisableControls y EnableControls del DataSet, pues probablemente estés ingresando con el DBGrid conectado, y mientras Windows intenta actualizar la pantalla, se presenta lentitud... aquí un ejemplo...

 

DBGrid1.DataSource.DataSet.DisableControls;

 

{metes todo el proceso arriba descrito}

 

DBGrid1.DataSource.DataSet.EnableControls;

 

un consejo... es más rápido Inc(actual) que actual := actual + 1;


  • 0

#6 luk2009

luk2009

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.003 mensajes
  • LocationSanto Domingo

Escrito 08 mayo 2017 - 06:33

I'm not dead, just busy!

 

revisa este hilo, por si te sirve de ayuda

Enviado desde mi KFFOWI mediante Tapatalk


  • 0

#7 poliburro

poliburro

    Advanced Member

  • Administrador
  • 4.933 mensajes
  • LocationMéxico

Escrito 08 mayo 2017 - 07:37

Para situaciones de este estilo lo mejor es usar Threads....


  • 0