德尔福 XE2
我有一个带有 TMemo 的表单,我想显示应用程序启动的几个服务中发生了什么。
我正在运行的内容:
- idHTTPServer 与 idContext 一起运行以响应请求
- 从 Dropbox 下载更新的线程
- idUDPServer 响应 UDP 请求
- 另一个线程处理一些数据库的东西。
- 主应用线程也需要添加日志
基本上,我需要知道如何创建一个标准的、统一的、线程安全的方式来将日志消息传送到我的 TMemo 并让用户了解正在发生的事情。
德尔福 XE2
我有一个带有 TMemo 的表单,我想显示应用程序启动的几个服务中发生了什么。
我正在运行的内容:
基本上,我需要知道如何创建一个标准的、统一的、线程安全的方式来将日志消息传送到我的 TMemo 并让用户了解正在发生的事情。
由于您已经在使用 Indy,您可以使用 Indy 的TIdSync
(同步)或TIdNotify
(异步)类来TMemo
安全地访问。出于简单的日志记录目的,我会使用TIdNotify
,例如:
type
TLog = class(TIdNotify)
protected
FMsg: string;
procedure DoNotify; override;
public
class procedure LogMsg(const AMsg; string);
end;
procedure TLog.DoNotify;
begin
Form1.Memo1.Lines.Add(FMsg);
end;
class procedure TLog.LogMsg(const AMsg: string);
begin
with TLog.Create do
try
FMsg := AMsg;
Notify;
except
Free;
raise;
end;
end;
然后你可以像这样在任何线程中直接调用它:
TLog.LogMsg('some text message here');
基本上,您可以构建一个接收所有消息的线程(这里,它是一个函数 AddEvent)。消息被排队(和时间戳)并在可能的情况下写入备忘录(如果您处于繁重的负载下......)。
如果备忘录超过行数,不要忘记清理备忘录,添加异常处理等......
我使用这样的东西:
TThreadedMsgEvent = class( TThread )
private
FLock : TCriticalSection;
FStr : TQueue<String>;
FMemo : TMemo;
function GetEvent : String;
protected
procedure Execute; override;
public
procedure AddEvent( aMsg : String );
constructor Create( AMemo: TMemo );
destructor Destroy; override;
end;
implementation
{ TThreadedMsgEvent }
procedure TThreadedMsgEvent.AddEvent(aMsg: String);
begin
FLock.Acquire;
FStr.Enqueue( FormatDateTime('DD/MM/YY HH:NN:SS.ZZZ',Now)+ ' : '+ aMsg );
FLock.Release;
end;
constructor TThreadedMsgEvent.Create(aMemo: TMemo);
begin
inherited Create(True);
FreeOnTerminate := False;
FOnMessage := ACallBack;
FStr := TQueue<String>.Create();
FLock := TCriticalSection.Create;
FMemo := aMemo;
Resume;
end;
destructor TThreadedMsgEvent.Destroy; override;
begin
FreeAndNil( FStr );
FreeAndNil( FLock );
end;
procedure TThreadedMsgEvent.Execute;
begin
while not Terminated do
begin
try
if (FStr.Count > 0) then
begin
if Assigned( aMemo ) then
begin
TThread.synchronize( procedure
begin
FMemo.Lines.Add( GetEvent );
end; );
end;
end;
except
end;
TThread.Sleep(1);
end;
end;
function TThreadedMsgEvent.GetEvent: String;
begin
FLock.Acquire;
result := FStr.Dequeue;
FLock.Release;
end;
您还可以使用 Windows 消息通知此线程。这可能会更容易,因为您不需要在您的课程中引用此线程。