Ir al contenido



Foto

I'm not dead, just busy!


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

#1 cHackAll

cHackAll

    Advanced Member

  • Administrador
  • 598 mensajes

Escrito 09 febrero 2009 - 03:12

Es muy común que nuestras aplicaciones aparenten estar “colgadas” cuando realizan alguna operación compleja; dicha operación puede ser realizada por el sistema operativo al haberse llamado a una determinada API, en la espera de la finalización de un “Commit” por un motor de base de datos, por que “cargamos” con una montaña de información a un componente de terceros o por otra razón.

Cuando la causa de dicho problema es un bucle que el propio programador ha escrito, comúnmente opta por llamar a “Application.ProcessMessages” en cada repetición para ir liberando la cola de mensajes, con lo cual WM_PAINT, WM_MOUSEMOVE y otros mensajes, al ser procesados refrescan el estado de la ventana. Conociendo también el inicio y el final de dicho proceso incluimos una barra de progreso en la aplicación y junto a la ya citada llamada solucionamos el problema.

Pero cuando la operación dura un tiempo indeterminable y/o es imposible incluir dicha llamada porque el “bucle” se encuentra en un lugar inaccesible, llega a ser complicado asegurarse que el usuario sepa que la aplicación está “ocupada” y no puede responde adecuadamente.

Las aplicaciones se quedan “colgadas” porque el hilo principal (el encargado de procesar los mensajes) no puede procesar la cola de mensajes porque está “ocupado”. En dicho contexto la solución sería “introducir” el proceso “complicado” en un hilo adicional pero esto puede llegar a ser todo una hazaña. Tampoco es aconsejable procesar los eventos desde otro hilo porque comúnmente hacemos aplicaciones que trabajen en varios hilos.

Para solucionarlo adjunto una unidad que implementa dos funciones, la primera se encarga de crear una nueva ventana de progreso compatible con las últimas versiones de Windows en un hilo nuevo, el cual procesa sus propios mensajes mientras nuestra aplicación se encuentra realizando una determinada operación. La segunda llamada cierra dicha barra de progreso utilizando un evento como método de sincronización con el hilo previamente creado.

Ejemplos;

delphi
  1. uses _Busy;
  2.  
  3. procedure TForm1.Button1Click(Sender: TObject);
  4. begin
  5. BusyBegin('Haciendo "algo"...', Handle);
  6.  
  7. // ReadFile(hCOM, Buffer, SizeOf(Buffer), Count, nil);
  8. // StartService(hService, 0, PPChar(0)^);
  9. // connect(hSocket, name, SizeOf(Addr));
  10. // Busca('xxx*.mp*');
  11. // Hell.CommitTrans;
  12. // etc, etc...
  13. Sleep(6666);
  14.  
  15. BusyEnd;
  16. end;


delphi
  1. program Delphi2010;
  2.  
  3. uses
  4. Forms, _Busy,
  5. Unit1 in 'Unit1.pas' {Form1};
  6.  
  7. begin
  8. Application.Initialize;
  9. BusyBegin('Iniciando...', Application.Handle);
  10. Application.CreateForm(TForm1, Form1);
  11. Application.CreateForm(TForm2, Form2);
  12. Application.CreateForm(TForm3, Form3);
  13. Application.CreateForm(TForm4, Form4);
  14. Application.CreateForm(TForm5, Form5);
  15. Application.CreateForm(TForm6, Form6);
  16. // ...
  17. BusyEnd;
  18. Application.Run;
  19. end.

Enjoy!

Archivos adjuntos


  • 0

#2 Caral

Caral

    Advanced Member

  • Administrador
  • 4.218 mensajes
  • LocationCosta Rica

Escrito 09 febrero 2009 - 03:36

Hola
Gracias amigo, siempre con estos aportes geniales. (y)
Saludos
  • 0

#3 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 13.819 mensajes
  • LocationMéxico

Escrito 09 febrero 2009 - 03:39

Hey

El viernes precisamente estabamos enecumeme y yo viendo un asunto con su programa MTF que está elaborando y teniamos este problema al ejecutar una DDL en un script queriendo mostrar "algo" mientras se ejecutaba y terminamos por claudicar :s :$.

Y vaya que esta es la respuesta a ese penoso asunto :$

Muchas gracias brother. (y)

Salud OS
  • 0

#4 Kipow

Kipow

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 228 mensajes
  • LocationGuatemala

Escrito 09 febrero 2009 - 03:56

Buen aporte, todo con tal de que los usuarios impaciente no nos cierren la aplicacion por no saber que esta trabajando. me parece excelente la opcion.
  • 0

#5 eduarcol

eduarcol

    Advanced Member

  • Administrador
  • 4.481 mensajes
  • LocationVenezuela

Escrito 09 febrero 2009 - 03:59

muy bueno,  8-|
  • 0

#6 cHackAll

cHackAll

    Advanced Member

  • Administrador
  • 598 mensajes

Escrito 09 febrero 2009 - 04:00

Gracias a todos, solo me queda comentar que en el pasado publique una version previa de "_Busy" que es más robusta y tiene algunas fallas.

Salud!
  • 0

#7 Caral

Caral

    Advanced Member

  • Administrador
  • 4.218 mensajes
  • LocationCosta Rica

Escrito 09 febrero 2009 - 04:39

Hola

Gracias a todos, solo me queda comentar que en el pasado publique una version previa de "_Busy" que es más robusta y tiene algunas fallas.

Salud!

Ah, entonces el zip debería de poner Versión: _Busy.1.2  (sin fallas) (y)
Esto con el fin de irnos actualizando con las versiones. (y) (y)
Saludos
  • 0

#8 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.163 mensajes
  • LocationArgentina

Escrito 09 febrero 2009 - 04:51

Hola,
Es de admirar lo que haces.
Ya me gustaría poder tener la décima parte de tus conocimientos.

No entiendo mucho el código, pero seguramente funciona a las diez mil maravillas :)... tendré que probarlo, ver como se comporta y estudiar las API involucradas.

De forma un tanto resumida, y pobre de lo que podría llegar a comprender... lo que tu código hace ¿es valerse de un hilo y ponerse a la escucha de la cola de mensajes y actuar en consecuencia, mientras "actualiza" la pantalla?

Entiendo que "centraliza" todo en un sólo lugar, de ese modo se evita dispersar hilos y ProcessMessages; más el código me confunde más que un poquito :p.

Saludos,
  • 0

#9 cHackAll

cHackAll

    Advanced Member

  • Administrador
  • 598 mensajes

Escrito 09 febrero 2009 - 05:33

Hola


Gracias a todos, solo me queda comentar que en el pasado publique una version previa de "_Busy" que es más robusta y tiene algunas fallas.

Salud!

Ah, entonces el zip debería de poner Versión: _Busy.1.2  (sin fallas) (y)
Esto con el fin de irnos actualizando con las versiones. (y) (y)
Saludos


Pues la versión antigua es funcional, tiene una barra de progreso dibujada por mi lo que ya no se ve tan bien en Vista & Se7en. También están un buen numero de errores que tan solo ahora puedo notar y corregir :$.

En todo caso queda la diferencia en las fechas de publicacion y la anterior aclaración.

Hola,
Es de admirar lo que haces.
Ya me gustaría poder tener la décima parte de tus conocimientos.


Gracias Delphius, espero te sea util ;)

...lo que tu código hace ¿es valerse de un hilo y ponerse a la escucha de la cola de mensajes y actuar en consecuencia, mientras "actualiza" la pantalla?

Entiendo que "centraliza" todo en un sólo lugar, de ese modo se evita dispersar hilos y ProcessMessages; más el código me confunde más que un poquito :p.

Saludos,


Técnicamente el hilo que crea BusyBegin crea a su vez una nueva ventana con su propia cola de mensajes, al ser totalmente independiente de nuestra aplicación funcionará aunque la nuestra este "casi" colgada.

Trabajando con APIs (GetMessage y DispatchMessage) no "existe" la necesidad de involucrarse con la VCL (Application.ProcessMessages), lo que nos permite usar la unidad hasta en una aplicación tipo consola.

Asi mismo el SO se encargará de dar todo el efecto visual y de procesar como debe de ser todos los mensajes propios de la clase "msctls_progress32".

Salud!
  • 0

#10 Rolphy Reyes

Rolphy Reyes

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.090 mensajes
  • LocationRepública Dominicana

Escrito 09 febrero 2009 - 07:27

Excelente, gracias por tu aporte.

Veo que utilizas 100% los mensajes para conseguir tu cometido (por lo menos eso creo).
  • 0

#11 Rolphy Reyes

Rolphy Reyes

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.090 mensajes
  • LocationRepública Dominicana

Escrito 10 febrero 2009 - 08:01

Saludos.

Encontré este hilo que en cierto modo hace referencia a lo comentado por cHackAll.
  • 0

#12 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.163 mensajes
  • LocationArgentina

Escrito 10 febrero 2009 - 08:24

Saludos.

Encontré este hilo que en cierto modo hace referencia a lo comentado por cHackAll.

Hola Rolphy,
Si me disculpas, me tomé el atrevimiento de modificar el link. Tenía una "basurita" al final ;).
  • 0

#13 cHackAll

cHackAll

    Advanced Member

  • Administrador
  • 598 mensajes

Escrito 11 febrero 2009 - 05:02

Excelente, gracias por tu aporte.


Provecho!

Veo que utilizas 100% los mensajes para conseguir tu cometido (por lo menos eso creo).


Pues es un tema de procesamiento de mensajes.

...Encontré este hilo que en cierto modo hace referencia a lo comentado por cHackAll.


^o|

This issue is simple; main project (.dpr) into the main thread calls an Application.Run, this method enters in a loop and calls each time the method Application.HandleMessages doing something like this “if not Application.ProcessMessage then OnIdle”.

Then, if the message queue is empty OnIdle will be called and call ProcessMessage with an empty messages queue is an stupid idea.


Con respecto a algun comentario de dicho enlace, he podido ver algun nivel de verificacion del MainThreadID en la VCL (multi-threading), pero tengo mis reservas.

Salud!
  • 0

#14 enecumene

enecumene

    Webmaster

  • Administrador
  • 7.394 mensajes
  • LocationRepública Dominicana

Escrito 12 febrero 2009 - 05:53

Hola ChackAll, muy interesante el código, intenté aplicarlo en una de mis aplicaciones y obtengo estos errores:

  [Error] WARNING. Duplicate resource(s):
  [Error]  Type 24 (user-defined), ID 1:
  [Error]    File c:\program files\borland\delphi7\Lib\WindowsXP.RES resource kept; file c:\program files\borland\delphi7\Lib\WindowsXP.res resource discarded.


¿Qué podría ser?, ¿qué hago mal?.

Saludos.
  • 0

#15 cHackAll

cHackAll

    Advanced Member

  • Administrador
  • 598 mensajes

Escrito 13 febrero 2009 - 05:28

He reemplazado el adjunto del primer post anulando dicho recurso, gracias por hacermelo notar.

Salud
  • 0

#16 enecumene

enecumene

    Webmaster

  • Administrador
  • 7.394 mensajes
  • LocationRepública Dominicana

Escrito 14 febrero 2009 - 07:15

Excelente amigo, ahora sí, me ha encantado, funciona de "Pelos" :D (y).

Saludos.
  • 0

#17 JandoK

JandoK

    Advanced Member

  • Moderadores
  • PipPipPip
  • 838 mensajes
  • LocationMexico

Escrito 30 marzo 2009 - 08:14

Hola  Mr. Creador de esta herremienta ... [ léase cHackAll ]  :p :p :p

Tengo un detallito con dicha Unit, para generar la ventanita de 'Busy' ...

Por el principio... Tengo una ventana (Form1) ... en la cual creo dinamicamente en el evento OnShow
varios componentes TCheckBox, en relacion a los valores que tengo almacenados en una Tabla.
Como dichos valores estan divididos por categorias, entonces tengo:

CATEGORIA    VALOR
        1              A
        1              B
        1              C
        2              D
        2              E
        3              F
        3              G
        4              H
        5              I

Mi idea es agragar TODOS los TCheckBox (que vienen a ser todos los datos del campo VALOR) ... de un color
diferente, dependiendo de la CATEGORIA a la que correspondan.  Esta parte YA esta resuelta (creo) .



delphi
  1. procedure TfrmInsertarVarios.PonerCheckboxs(catnum, catnom, tipnum, tipnom : string);
  2. var
  3.   chkbxNombre : string;
  4. begin
  5.   chkbxNombre := 'Estudio' + catnum + tipnum;  // el nombre del componente es 'Estudio' + CATEGORIA + VALOR
  6.   TCheckBox.Create(Self).Name := chkbxNombre;
  7.  
  8.   with TCheckBox(FindComponent(chkbxNombre)) do
  9.   begin
  10.     Font.Style := [fsBold];
  11.     Font.Color := ListaColores[StrToInt(catnum)];  // este es un Array con los colores que va a tomar cada CATEGORIA
  12.     Left := chkbxLeft;
  13.     Top := chkbxTop;
  14.     Visible := True;
  15.     Caption := tipnom;
  16.     Checked := False;
  17.     Width := chkbxCalcularAncho(tipnom); //una funcion para adecuar el ancho del TCheckbox y mostrar todo el valor del Caption
  18.     Parent := frmInsertarVarios.sbEstudios;  //sbEstudios es un componente TScrollBox
  19.   end;
  20. end;




El detalle surge con LOS COLORES de la fuente del TCheckBox, si NO agrego la unidad '_Busy'
los TcheckBox si toman los colores. Pero si agrego el '_Busy', la fuente de los TCheckBox NO
cambia, se queda en negro (color por default) ...

Espero haberme dado a entender...  y haber si me pueden ayudar para ver que esta mal  :s :s :s

Gracias...

Salu2!!!!!!!
  • 0

#18 cHackAll

cHackAll

    Advanced Member

  • Administrador
  • 598 mensajes

Escrito 31 marzo 2009 - 05:53

Hola JandoK, a mi me funciona 8-)



delphi
  1. uses _Busy;
  2.  
  3. procedure TForm1.Button1Click(Sender: TObject);
  4. const ListaColores: array [0..5] of TColor = (clRed, clYellow, clGreen, clBlue, clPurple, clSilver);
  5. var Index: Integer;
  6. begin
  7. for Index := Low(ListaColores) to High(ListaColores) do
  8.   with TCheckBox.Create(Self) do
  9.   begin
  10.     Font.Style := [fsBold];
  11.     Font.Color := ListaColores[Index];
  12.     Caption := 'Muestra todo el codigo necesario!!!  x' + IntToStr(Index);
  13.     Left := 10;
  14.     Top := Index * 12;
  15.     Visible := True;
  16.     Width := 666;
  17.     Parent := Self;
  18.   end;
  19. end;
  20.  
  21. procedure TForm1.Button2Click(Sender: TObject);
  22. begin
  23. BusyBegin('Ctrl+C imposible!');
  24. Button1Click(nil);
  25. BusyEnd;
  26. end;


  • 0

#19 JandoK

JandoK

    Advanced Member

  • Moderadores
  • PipPipPip
  • 838 mensajes
  • LocationMexico

Escrito 01 abril 2009 - 05:58

no pues nop ....

asi como TU lo tienes, NO pone los Checkbox del respectivo color...  :s :s :s :s

solo me toma el estilo  (Bold) ...

en fin... seguire buscando donde esta el detalle.... (por que ahora, aunque no tenga agregada la unidad _Busy ... Sigue SIN TOMARME en cuenta el color  :s :s :s )

gracias...

salu2!!!!!!!
  • 0

#20 cHackAll

cHackAll

    Advanced Member

  • Administrador
  • 598 mensajes

Escrito 01 abril 2009 - 06:11

no pues nop ....


Imagen Enviada

He reemplazado el adjunto del primer post anulando dicho recurso...


Descarga _Busy.pas nuevamente... es un tema relacionado con los themes del Gí¼indos, NO con _Busy!
  • 0