我正在使用Delphi 2007和线程。
我的问题(对不起,我会尝试更好地解释):
1)我创建了一个文件" utilities.pas"我有更多功能的地方。 2)我创建了一个新程序,在这个程序中我有一个线程 3)在线程的execute方法中,我在我的文件中调用了一个函数" utilities.pas"。 此功能使用聪明的组件(tclftp)连接到ftp。此组件在专用事件中记录服务器响应。我想做的是将日志保存在字符串列表中,然后将字符串列表发送回调用线程。
这是文件" utilities.pas":
的一部分// I created TEventHandlers because it's the only way to assign the event runtime
// without having a class
type
TEventHandlers = class
procedure clFtp1SendCommand(Sender: TObject; const AText: string);
end;
var EvHandler: TEventHandlers;
// this is the porcedure called from the thread. i want to send the stringlist
// back to it containing the ftp log
procedure Test(VAR slMain: tStringlist);
var cFTP: TclFtp;
begin
cFTP := TclFtp.Create(nil);
cFTP.Server := 'XXX';
cFTP.UserName := 'XXX';
cFTP.Password := 'XXX';
cFTP.OnSendCommand := EvHandler.clFtp1SendCommand;
// i connect to the ftp
cFTP.Open;
FreeAndNil(cFTP);
end;
procedure TEventHandlers.clFtp1SendCommand(Sender: TObject; const AText: string);
begin
// here the component (cftp) sends me back the answer from the server.
// i am logging it
// HERE IT'S THE PROBLEM:
// I can't reach slMain from here.....
slmain.add(Atext);
end;
这是调用线程:
procedure TCalcThread.Execute;
var slMain: tstringlist;
begin
inherited;
slmain := tstringlist.create(nil);
Test(slmain);
if slMain.count > 0 then
slMain.savetofile('c:\a.txt');
// i won't free the list box now, but in the thread terminated.
end;
这是主程序:
procedure TfMain.ThreadTerminated(Sender: TObject);
Var ExThread: TCalcThread;
begin
ExThread := (Sender as TCalcThread);
if ExThread.slMain.Count > 0 then
ExThread.slMain.SaveToFile('LOG\Errori.log');
freeandnil(slMain);
end;
请有人帮我解决这个问题吗?我真的不知道该怎么做。 我希望现在更清楚。
P.S。谢谢你的所有答案..
答案 0 :(得分:0)
我认为一种(BAD)方法是在主线程中或在设计时创建组件池,并为每个线程分配一个组件。即5个cFTP实例,5个字符串列表,5个线程。
更新:马丁詹姆斯指出为什么这是一个可怕的想法,我同意。所以不要这样做。邮寄是一种威慑。
答案 1 :(得分:0)
另一种方法是让你的线程对象拥有自己的stringlist实例和自己的cFTP。如果你需要一个所有写入的“主线程”(可能是每个线程完成的内容的摘要),请使用以下类: Tilo Eckert的TThreadStringList http://www.swissdelphicenter.ch/torry/showcode.php?id=2167
答案 2 :(得分:0)
拦截线程类中的事件,并从该处理程序中触发自己的类型事件。同步此通话!并尝试阻止全局变量。所有这些如下:
type
TFtpSendCommandEvent = procedure(Mail: TStrings; const AText: String) of object;
TMyThread = class(TThread)
private
FclFtp: TclFtp;
FslMail: TStrings;
FOnFtpSendCommand: TFtpSendCommandEvent;
FText: String;
procedure clFtpSendCommand(Sender: TObject; const AText: String);
procedure DoFtpSendCommand;
protected
procedure Execute; override;
public
// You could add this property as parameter to the constructor to prevent the
// need to assign it separately
property OnFtpSendCommand: TFtpSendCommandEvent read FOnFtpSendCommand
write FOnFtpSendCommand;
end;
// If you dont want to make this a property or private field of the thread class:
var
EvHandler: TFtpSendCommandEvent;
{ TMyThread }
procedure TMyThread.clFtpSendCommand(Sender: TObject; const AText: string);
begin
// Store the AText parameter temporarily in a private field: Synchronize only
// takes a parameterless method
FText := AText;
Synchronize(DoFtpSendCommand);
end;
procedure TMyThread.DoFtpSendCommand;
begin
if Assigned(FOnFtpSendCommand) then
FOnFtpSendCommand(FslMail, FText);
// Or, if you really like to use that global variable:
if Assigned(EvHandler) then
EvHandler(FslMail, FText);
end;
procedure TMyThread.Execute;
begin
...
FclFtp := TclFtp.Create(nil);
FslMail := TStringList.Create(nil);
try
FclFtp.Server := 'XXX';
FclFtp.UserName := 'XXX';
FclFtp.Password := 'XXX';
FclFtp.OnSendCommand := clFtpSendCommand;
FclFtp.Open;
finally
FreeAndNil(FclFtp);
FreeAndNil(FslMail);
end;
...
end;