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;
uses _Busy; procedure TForm1.Button1Click(Sender: TObject); begin BusyBegin('Haciendo "algo"...', Handle); // ReadFile(hCOM, Buffer, SizeOf(Buffer), Count, nil); // StartService(hService, 0, PPChar(0)^); // connect(hSocket, name, SizeOf(Addr)); // Busca('xxx*.mp*'); // Hell.CommitTrans; // etc, etc... Sleep(6666); BusyEnd; end;
program Delphi2010; uses Forms, _Busy, Unit1 in 'Unit1.pas' {Form1}; begin Application.Initialize; BusyBegin('Iniciando...', Application.Handle); Application.CreateForm(TForm1, Form1); Application.CreateForm(TForm2, Form2); Application.CreateForm(TForm3, Form3); Application.CreateForm(TForm4, Form4); Application.CreateForm(TForm5, Form5); Application.CreateForm(TForm6, Form6); // ... BusyEnd; Application.Run; end.
Enjoy!