我有一个Query
,并在我的Thread
中打开它。它可以正常工作,我不想使用Synchronize
,因为Synchronize
使得主Form
在Query
未完成提取时不响应。
当关闭显示的Form
blow错误时:
系统错误。代码:1400。无效的窗口句柄
type
TMyThread = class(TThread)
public
procedure Execute; override;
procedure doProc;
end; { type }
.
.
.
procedure TMyThread.doProc;
begin
Form1.Query1.Open;
end;
procedure TMyThread.Execute;
begin
inherited;
doProc;
end;
.
.
.
procedure TForm1.Button1Click(Sender: TObject);
begin
thrd := TMyThread.Create(True);
thrd.FreeOnTerminate := True;
thrd.Resume;
end;
注意:
Query
有很多记录。
最佳答案
问题在于,VCL是而不是线程安全的。
为了使查询与其他所有事情并行执行,您必须将其与表单分离。
这意味着您必须使用代码在运行时创建查询:
type
TMyThread = class(TThread)
private
FQuery: TQuery;
FOnTerminate: TNotifyEvent;
public
constructor Create(AQuery: TQuery);
destructor Destroy; override;
procedure Execute; override;
procedure doProc;
//Add an event handler to do cleanup on termination.
property OnTerminate: TNotifyEvent read FOnTerminate write FOnTerminate;
end; { type }
constructor TMyThread.Create(AQuery: TQuery);
begin
inherited Create(True);
FQuery:= AQuery;
end;
procedure TMyThread.doProc;
begin
FQuery1.Open;
Synchronize(
//anonymous method, use a separate procedure in older Delphi versions
procedure
begin
Form1.Button1.Enabled:= true; //reenable the button when we're done.
end
);
end;
procedure TMyThread.Execute;
begin
inherited;
doProc;
end;
destructor TMyThread.Destroy;
begin
if Assigned(FOnterminate) then FOnTerminate(Self);
inherited;
end;
在Button1的
OnClick
中,您将执行以下操作:type
TForm1 = class(TForm)
private
AQuery: TQuery;
...
end; {type}
procedure TForm1.Button1Click(Sender: TObject);
begin
Button1.Enabled:= false; //disable the button so it cannot be started twice.
thrd.Free;
AQuery:= TQuery.Create;
AQuery.SQL.Text:= .....
thrd := TMyThread.Create(AQuery);
thrd.OnTerminate:= MyTerminationHandler;
thrd.FreeOnTerminate:= False;
thrd.Resume;
end;
最后,将清理代码分配给线程的终止处理程序。
如果销毁线程中的Query,则不能使用
FreeOnTerminate:= true
,但必须自己释放线程。procedure TForm1.MyTerminationHandler(Sender: TObject);
begin
FreeAndNil(AQuery);
end;
警告
仅当您启动1个线程时,此代码才有效。
如果您想多次启动该线程(即同时运行多个查询),则必须创建一个线程数组,例如:
TQueryThreads = record
MyThread: TMyThread;
MyQuery: TQuery;
constructor Create(SQL: string);
end; {record}
TForm1 = class(TForm)
private
Threads: array of TQueryThreads;
....
end; {TForm1}
请注意,此代码在BDE中不起作用,因为该库不支持同时运行多个查询。
如果要这样做,则必须使用ZEOS或类似的东西。
根据TLama的建议:
我建议将BDE TQuery组件切换为ADO,或下载类似ZEOS components的东西。 BDE非常过时,并且有很多古怪的地方,因为它不再被维护,因此永远不会得到解决。
剩下的唯一问题是,如果关闭
Form1
,则清理连接。如果这是您的主要形式,那真的没有关系,因为您的整个应用程序都将崩溃。
如果不是您的主要表单,则需要通过填充
OnCanClose
处理程序来禁用关闭表单。TForm1.CanClose(Sender: TObject; var CanClose: boolean);
begin
CanClose:= thrd.Finished;
end;
关于multithreading - 在线程(Delphi)中打开查询时关闭表单时出错,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23196509/