Esta pregunta es mucho más compleja de lo que inicialmente se pensaba; que lo hace una buena pregunta.
Inicialmente pensé que Application.processmessages era el camino correcto, sin embargo es un campo de minas potencial a menos que sea cuidadoso (gracias @skamradt por señalar esto). Tampoco ayuda con una sola llamada de bloqueo.
Se necesita un hilo de fondo de la siguiente manera: (gracias @mghie por señalar los errores que ahora se resuelven ). Todavía puede haber problemas con el objeto de la base de datos llamado en diferentes hilos, por lo que el hilo de fondo puede necesitar tener su propia conexión de base de datos para esta operación (si es posible).
En el siguiente ejemplo, no he mostrado específicamente el código para crear y destruir la ventana de progreso, ya que hará que el código sea aún más largo, y es fácil de hacer.
Así que tenemos dos objetos de hacer esto:
En primer lugar el subproceso de fondo para procesar la consulta.
unit BackgroundProcess;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs, windows;
const
WM_MY_BACKGROUNDNOTIFY = WM_USER + 555; { change this }
NOTIFY_BEGIN = 22;
NOTIFY_END = 33;
type
TBackgroundQueryThread = class(TThread)
private
hwndnotify : HWND;
protected
procedure Execute; override;
public
constructor Create(owner: TForm);
end;
implementation
constructor TBackgroundQueryThread.Create(owner: TForm) ;
begin
inherited Create(False);
hwndnotify := owner.Handle;
FreeOnTerminate := true;
resume;
end;
procedure TBackgroundQueryThread.Execute;
begin
PostMessage(hwndnotify, WM_MY_BACKGROUNDNOTIFY, NOTIFY_BEGIN, 0);
Sleep(2000); (* Query goes here. *)
PostMessage(hwndnotify, WM_MY_BACKGROUNDNOTIFY, NOTIFY_END, 0);
end;
end.
La forma que invoca la consulta:
unit mainform;
interface
uses
Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
StdCtrls, ExtCtrls, windows, BackgroundProcess;
type
TForm1 = class(TForm)
private
frm : tFrmPopupElapsed;
{ private declarations }
procedure OnMyBackgrounNotify(var Msg: TMessage); message WM_MY_BACKGROUNDNOTIFY;
public
{ public declarations }
end;
var
Form1: TForm1;
implementation
procedure TForm1.OnMyBackgrounNotify(var Msg: TMessage);
begin
if (msg.WParam = NOTIFY_BEGIN) THEN
BEGIN
if (frm = nil) THEN
BEGIN
frm := tFrmPopupElapsed.Create(nil);
frm.Init; // this procedure enables the timer
frm.Show();
END;
END;
if (msg.WParam = NOTIFY_END) THEN
BEGIN
if (frm <> nil) THEN
BEGIN
frm.Close;
END;
END;
end;
end.
¿Qué base de datos? Al menos uno que conozco (DBISAM/ElevateDB) ofrece un evento OnProgress muy útil en su componente de consulta. Puede codificar en su informe el tiempo transcurrido, porcentaje completado, etc. –
sugerencia pequeña: pondría el 'try' antes de' frm.Init' – mjn
Tenga en cuenta que al llamar 'frm.Close' dará como resultado pérdidas de memoria a menos que el formulario tiene un controlador 'OnClose' que establece' caFree'. Usar 'frm.Release' sería mucho más seguro. – mghie