Я должен показать всплывающее окно перед выполнением запросов, показать, что время протекло, в то время как запрос SQL выполняется, и закройте то окно, когда запрос заканчивается.
На самом деле я делаю что-то вроде этого
var
frm : tFrmPopupElapsed;
// this form has a TTimer and a TLabel to show the elapsed time
// but the label is not updated, I tried using update and refresh
// but nothing happens
begin
frm := tFrmPopupElapsed.Create(nil);
try
frm.Init; // this procedure enables the timer
frm.Show();
ExecuteMyVeryLongQuery();
finally
frm.Close;
end;
end;
Как маркировка может быть обновлена для показа прошедшего времени, в то время как запрос выполняется? Используя таймер? Или поток?
Вам необходимо выполнить запрос асинхронно , позволяя тем временем обновлять форму.
Самый простой способ сделать это, не запачкая руки потоками , - это использовать библиотеку Андреаса Хаусладена AsynCalls .
Вы также можете ознакомиться с библиотекой OmniThread , написанной Примозом Габриелчичем.
Вам нужно будет запустить запрос в фоновом потоке, если вы хотите, чтобы пользовательский интерфейс реагировал во время выполнения запроса. Если запрос поддерживает отмену, вы также можете добавить кнопку отмены. Однако я считаю, что это поддерживают только запросы ADO.
Этот вопрос намного сложнее, чем предполагалось изначально; что делает это хорошим вопросом.
Сначала я подумал, что Application.processmessages - правильный путь, однако это потенциальное минное поле, если вы не будете осторожны (спасибо @skamradt за указание на это). Это также не помогает с единичным блокирующим звонком.
Фоновый поток необходим следующим образом: (спасибо @mghie за указание на ошибки, которые теперь устранены). По-прежнему могут возникать проблемы с вызовом объекта базы данных в разных потоках, поэтому фоновому потоку может потребоваться собственное соединение с базой данных для этой операции (если это возможно).
В приведенном ниже примере я специально не показывал код для создания и уничтожения окна прогресса, так как это сделает код еще длиннее, и это будет легко сделать.
Итак, для этого нам нужны два объекта:
Во-первых, фоновый поток для обработки запроса.
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.
Форма, которая вызывает запрос:
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.