我需要在执行查询之前显示一个弹出窗口,显示执行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;
如何更新标签以显示查询执行时的已用时间?使用计时器?还是线程?
答案 0 :(得分:4)
您需要运行查询异步,允许您在此期间更新表单。
最简单的方法就是使用线程来解决问题的方法是使用Andreas Hausladen的AsynCalls library。
您还可以查看Primoz Gabrijelcic的 OmniThread Library 。
答案 1 :(得分:1)
如果希望用户界面在查询执行期间响应,则需要在后台线程中运行查询。如果查询支持取消,您还可以添加取消按钮。不过,我相信只有ADO查询支持这一点。
答案 2 :(得分:0)
这个问题比最初设想的要复杂得多;这使它成为一个很好的问题。
最初我认为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.