请问:关于等待对话框和线程,内详
请教:关于等待对话框和线程,内详
点击“查询”时,创建出一个查询线程,进行向服务器查询数据的耗时处理。同时,在主线程内创建一个带有animate的等待对话框,showmodal。由于查询线程中,返回的数据要填充到主线程DBGrid1所绑定的数据集里,所以查询线程的Excute里调用了主线程的成员函数进行查询,查询结束后,将等待对话框的ModalResult置为IDOK。
现在是,如果查询线程里不用Synchronize进行同步,那么等待对话框里能够正常显示(包括animate能正常播放),但大概再查询几次,就会出现“canvas does not allow drawing”的错误。如果不用Synchronize进行同步,那么等待对话框就是一片空白。
焦头烂额中,表述不清楚,还是看大概的代码吧。
【查询按钮的点击事件】:
procedure TForm1.btnQryClick(Sender: TObject);
var
wait_form: TMyWaitWnd;
begin
...
F_aParamValue := ...; // 查询条件赋值
wait_form := TMyWaitWnd.Create(nil);
wait_form.Fanimate.Active := True;
try
ThreadWaitWnd.Create(wait_form, Self.LoadData);
wait_form.ShowModal;
finally
wait_form.Fanimate.Active := False;
wait_form.Close;
wait_form.Free;
end;
...
end;
【被查询子线程调用的函数】:
procedure TForm1.LoadData();
begin
GetBaInfoList(F_aParamValue, cds1); // 从服务器查询数据,填充到DBGrid1绑定的数据集cds1里。
end;
【查询子线程】:
unit WaitWndThread;
interface
uses
Classes, windows, WaitWnd, ActiveX;
type
ThreadWaitWnd = class(TThread)
private
{ Private declarations }
myProc: TThreadMethod;
MyWaitWnd : TMyWaitWnd;
public
{ Public declarations }
protected
procedure Execute; override;
published
constructor Create(wait_form: TMyWaitWnd; call_back: TThreadMethod);
end;
implementation
constructor ThreadWaitWnd.Create(wait_form: TMyWaitWnd; call_back: TThreadMethod);
begin
inherited Create(False);
MyWaitWnd := wait_form;
myProc := call_back;
end;
procedure ThreadWaitWnd.Execute;
var
msg: TMsg;
begin
inherited;
CoInitialize(nil);
try
Synchronize(myProc);
finally
MyWaitWnd.ModalResult := IDOK;
end;
CoUninitialize;
end;
end.
------解决方案--------------------
用Synchronize相当于在主线程里执行查询,会阻塞主线程的消息循环,因此你的画面会冻结住。这样起一个线程有调用Synchronize的行为说白了就是脱了裤子放屁。
如果不用Synchronize,那你直接在非主线程的线程里执行查询,这样的话,就要注意线程同步,主线程和你的查询线程访问共同资源的同步问题,由于VCL的界面不是多线程安全的,所以你如果没有主动处理多线程同步的话,就会出现那个“canvas does not allow drawing”
点击“查询”时,创建出一个查询线程,进行向服务器查询数据的耗时处理。同时,在主线程内创建一个带有animate的等待对话框,showmodal。由于查询线程中,返回的数据要填充到主线程DBGrid1所绑定的数据集里,所以查询线程的Excute里调用了主线程的成员函数进行查询,查询结束后,将等待对话框的ModalResult置为IDOK。
现在是,如果查询线程里不用Synchronize进行同步,那么等待对话框里能够正常显示(包括animate能正常播放),但大概再查询几次,就会出现“canvas does not allow drawing”的错误。如果不用Synchronize进行同步,那么等待对话框就是一片空白。
焦头烂额中,表述不清楚,还是看大概的代码吧。
【查询按钮的点击事件】:
procedure TForm1.btnQryClick(Sender: TObject);
var
wait_form: TMyWaitWnd;
begin
...
F_aParamValue := ...; // 查询条件赋值
wait_form := TMyWaitWnd.Create(nil);
wait_form.Fanimate.Active := True;
try
ThreadWaitWnd.Create(wait_form, Self.LoadData);
wait_form.ShowModal;
finally
wait_form.Fanimate.Active := False;
wait_form.Close;
wait_form.Free;
end;
...
end;
【被查询子线程调用的函数】:
procedure TForm1.LoadData();
begin
GetBaInfoList(F_aParamValue, cds1); // 从服务器查询数据,填充到DBGrid1绑定的数据集cds1里。
end;
【查询子线程】:
unit WaitWndThread;
interface
uses
Classes, windows, WaitWnd, ActiveX;
type
ThreadWaitWnd = class(TThread)
private
{ Private declarations }
myProc: TThreadMethod;
MyWaitWnd : TMyWaitWnd;
public
{ Public declarations }
protected
procedure Execute; override;
published
constructor Create(wait_form: TMyWaitWnd; call_back: TThreadMethod);
end;
implementation
constructor ThreadWaitWnd.Create(wait_form: TMyWaitWnd; call_back: TThreadMethod);
begin
inherited Create(False);
MyWaitWnd := wait_form;
myProc := call_back;
end;
procedure ThreadWaitWnd.Execute;
var
msg: TMsg;
begin
inherited;
CoInitialize(nil);
try
Synchronize(myProc);
finally
MyWaitWnd.ModalResult := IDOK;
end;
CoUninitialize;
end;
end.
------解决方案--------------------
用Synchronize相当于在主线程里执行查询,会阻塞主线程的消息循环,因此你的画面会冻结住。这样起一个线程有调用Synchronize的行为说白了就是脱了裤子放屁。
如果不用Synchronize,那你直接在非主线程的线程里执行查询,这样的话,就要注意线程同步,主线程和你的查询线程访问共同资源的同步问题,由于VCL的界面不是多线程安全的,所以你如果没有主动处理多线程同步的话,就会出现那个“canvas does not allow drawing”