Câu hỏi này phức tạp hơn nhiều so với dự kiến ban đầu; mà làm cho nó một câu hỏi hay.
Ban đầu tôi nghĩ Application.processmessages là đúng cách, tuy nhiên nó là một mỏ tiềm năng trừ khi bạn cẩn thận (nhờ @skamradt để chỉ ra điều này). Nó cũng không giúp đỡ với một cuộc gọi chặn duy nhất.
Chủ đề nền là cần thiết như sau: (cảm ơn @mghie vì đã chỉ ra các lỗi mà hiện đã được giải quyết). Vẫn có thể có vấn đề với đối tượng cơ sở dữ liệu được gọi trong các luồng khác nhau - do đó, luồng nền có thể cần phải có kết nối cơ sở dữ liệu riêng cho thao tác này (nếu có thể thực hiện được).
Trong ví dụ dưới đây tôi đã không được hiển thị cụ thể là mã cho việc tạo ra và phá hủy các cửa sổ tiến bộ vì nó sẽ làm cho đoạn code thậm chí lâu hơn, và dễ dàng để làm.
Vì vậy, chúng tôi cần hai đối tượng để thực hiện việc này:
Đầu tiên là chuỗi nền để xử lý truy vấn.
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.
Các hình thức mà gọi truy vấn:
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.
Cơ sở dữ liệu nào? Ít nhất một cái mà tôi biết (DBISAM/ElevateDB) cung cấp một sự kiện OnProgress rất tiện dụng trên thành phần truy vấn của họ. Bạn có thể viết mã để báo cáo thời gian trôi qua, phần trăm hoàn thành, v.v. –
gợi ý nhỏ: Tôi sẽ đặt 'try' trước' frm.Init' – mjn
Lưu ý rằng việc gọi 'frm.Close' sẽ dẫn đến rò rỉ bộ nhớ trừ khi biểu mẫu có một trình xử lý 'OnClose' đặt' caFree'. Sử dụng 'frm.Release' sẽ an toàn hơn nhiều. – mghie