我是熟悉Delphi中线程的新手。所以,我正在尝试创建一个简单的查询应用程序,为数据库调用一点并花一点时间,所以我想提醒用户有一个后台进程,并且必须耐心等待。
我尝试过很多样本,但是没有一个样本适合我,拜托,有人可以给我看一个可行的简单样本吗?
我知道我必须声明一种类型的TThread,使用Create和Override Execute ......等等。但是因为我失去了......
使用Delphi 7,SQL Server 2005和ADO,Windows XP sp3 .-
感谢。
答案 0 :(得分:52)
是的,你声明了一个继承自TThread的新类型:
TMyWorkerThread = class(TThread)
end;
然后为Execute()添加函数覆盖:
TMyWorkerThread = class(TThread)
public
procedure Execute; override;
end;
启动线程时将调用该过程。它将与您的主程序并行执行。我们来写吧。
procedure TMyWorkerThread.Execute;
begin
//Here we do work
DoSomeWork();
DoMoreWork();
//When we exit the procedure, the thread ends.
//So we don't exit until we're done.
end;
如何使用这个?假设您想在用户单击按钮时开始工作。您编写了一个OnClick处理程序:
procedure TMainForm.Button1Click(Sender: TObject);
begin
TMyWorkerThread.Create(false);
end;
就是这样。用户单击按钮后,您的线程将启动并继续执行您在Execute中编写的任何内容。如果用户再次单击该按钮,则另一个线程将启动,然后另一个线程 - 每次单击一个。它们都将并行运行,每个都执行在Execute()中写入的所有内容,然后结束。
假设您要检查工作是否结束。为此,您必须将引用存储在某个地方:
TMainForm = class(TForm)
{...skipped...}
public
MyWorkerThread: TThread;
end;
procedure TMainForm.Button1Click(Sender: TObject);
begin
//This time we make sure only one thread can be started.
//If one thread have been started already, we don't start another.
if MyWorkerThread<>nil then
raise Exception.Create('One thread have already been started!');
MyWorkerThread := TMyWorkerThread.Create(false);
end;
procedure TMainForm.Button2Click(Sender: TObject);
begin
//If the work is not over yet, we display message informing the user we're still working
if (MyWorkerThread<>nil) and (WaitForSingleObject(MyWorkerThread.Handle, 0)<>WAIT_OBJECT_0) then
MessageBox(Self.Handle, pchar("The work is not yet done!"), pchar("Still running"), MB_OK);
end;
如您所见,我们通过调用名为WaitForSingleObject的Windows函数来检查线程是否仍在运行。此函数等待线程完成工作,或超时已过,并且当我们指定超时为0时,如果线程尚未结束,它将立即存在。
答案 1 :(得分:32)
您可以在线程网上找到许多示例。如果您在线程内部使用ADO连接,唯一的特殊功能是您不能共享相同的连接 每个线程必须创建自己的连接,否则它们是相同的(应该遵循与任何其他线程相同的规则。)
我使用的样本是:
TADOSQLThread = class(TThread)
private
FADOQ: TADOQuery; // Internal query
FSQL: string; // SQL To execute
FID: integer; // Internal ID
public
constructor Create(CreateSuspended:Boolean; AConnString:String;
ASQL:string; IDThread:integer);
destructor Destroy; override;
procedure Execute(); override;
property ID:integer read FID write FID;
property SQL:string read FSQL write FSQL;
property ADOQ:TADOQuery read FADOQ write FADOQ;
end;
Create构造函数被覆盖,如下所示:
constructor TADOSQLThread.Create(CreateSuspended:Boolean; AConnString:String;
ASQL:string; IDThread:integer);
begin
inherited Create(CreateSuspended);
// ini
Self.FreeOnTerminate := False;
// Create the Query
FADOQ := TAdoquery.Create(nil);
// assign connections
FADOQ.ConnectionString := AConnString;
FADOQ.SQL.Add(ASQL);
Self.FID := IDThread;
Self.FSQL:= ASQL;
end;
执行方法非常简单:
procedure TADOSQLThread.Execute();
begin
inherited;
try
// Ejecutar la consulta
Self.FADOQ.Open;
except
// Error al ejecutar
...Error treattement
end;
end;
要启动并创建一个线程,您可以使用与此类似的代码:
//crear el Thread
th := TADOSQLThread.Create(True, mmConnection.Lines.Text, ASQL, AId);
// internal for me (for controled the number of active threads and limete it)
inc(numThreads);
// evento finalizacion
th.OnTerminate := TerminateThread;
// Ejecutarlo
th.Resume;
我创建了一个 TerminateThread 方法,在完成后接收线程控制。与其他线程唯一不同的是连接问题。您必须在每个线程上创建一个新连接,它不能与其他线程共享相同的ADOConnections 我希望这个例子对你有用。
此致