2

德尔福 XE2

我有一个带有 TMemo 的表单,我想显示应用程序启动的几个服务中发生了什么。

我正在运行的内容:

  • idHTTPServer 与 idContext 一起运行以响应请求
  • 从 Dropbox 下载更新的线程
  • idUDPServer 响应 UDP 请求
  • 另一个线程处理一些数据库的东西。
  • 主应用线程也需要添加日志

基本上,我需要知道如何创建一个标准的、统一的、线程安全的方式来将日志消息传送到我的 TMemo 并让用户了解正在发生的事情。

4

2 回答 2

7

由于您已经在使用 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');
于 2013-07-07T03:26:29.323 回答
4

基本上,您可以构建一个接收所有消息的线程(这里,它是一个函数 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 消息通知此线程。这可能会更容易,因为您不需要在您的课程中引用此线程。

于 2013-07-06T20:46:38.250 回答