Delphi XE5-需要奇怪的行为帮助 [英] Delphi XE5 - strange behavior help needed

查看:81
本文介绍了Delphi XE5-需要奇怪的行为帮助的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在处理TLogger类,该类将我的应用程序日志记录到文件中...

I'm working on TLogger class that is logging my application logs to file...

我必须设法将日志从文件发送到TMemo: 1.将TMemo分配给TLogger类,然后将True分配给DisplayInMemo属性,然后仅调用GetLogFromFile(); 2.调用GetLogsFromFile();然后Self.Memo1.Text:= TLogger.LogsResult;

I have to way of getting Logs from File to TMemo: 1. assign TMemo to TLogger class then, assign True to DisplayInMemo property, then just call GetLogFromFile(); 2. call GetLogsFromFile(); then Self.Memo1.Text := TLogger.LogsResult;

以下...注释的解决方案效果很好...未注释的解决方案仅每2单击一次按钮4即可起作用

Below... Commented solution works fine... Uncommented solution works only every 2 click on button 4

procedure TForm1.Button4Click(Sender: TObject);   // get log.file to memo
begin
  // automatic forwarding logs from File to TMemo - it works!
  //logger.DisplayMemo := Self.Memo1;
  //logger.DisplayInMemo := True;
  //logger.GetLogsFromFile();

  // tested - half-automatic method of formwarding logs to TMemo - works every 2 clicks :(
  logger.DisplayInMemo := False;
  logger.GetLogsFromFile();
  Self.Memo1.Text := logger.LogsResult;
end;

整个TLogger实施:

Whole TLogger implementation:

unit Logger;

interface

uses
  System.IOUtils, System.TypInfo, System.SysUtils, FMX.Forms, FMX.Dialogs, System.Classes, FMX.Graphics, FMX.ExtCtrls, LoggerThread, FMX.Memo;

type

  TLogger = class
  private
    FileName : String;                // name of file to log
    FilePath : String;                // path to app / log-file

    LStringResult : String;           // result of thread log.file reading
    LLoggerMemo : TMemo;              // copy of memo - place where GetLogsFromFile put results

    LDisplayInMemo : Boolean;         // bool - if True  GetLogsFromFile puts results to DisplayMemo, otherwise waiting in LogsResult
    NewLoggerThread : TLoggerThread;  // thread object - created in Create()

    procedure GetLogsFromFileThreadTerminateHandler(sender: TObject);

  public
    constructor Create(); overload;                     // open or create 'development.log'
    constructor Create(LogFileName : String); overload; // open or create LogFileName for logging
    destructor Destroy(); overload;                     // cleaner of TLogger object
    // main procedures
    procedure Log(LogString : String);                  // add line to log file
    procedure GetLogsFromFile();                        // get all logs from log file to string
    // settings, reading results,
    property DisplayInMemo : Boolean read LDisplayInMemo write LDisplayInMemo; //bool - if True  GetLogsFromFile puts results to DisplayMemo, otherwise waiting in LogsResult
    property LogsResult : String read LStringResult write LStringResult;       //string results after Getters from TLogger usage
    property DisplayMemo : TMemo read LLoggerMemo write LLoggerMemo;           // sets TMemo where results will be put if DisplayInMemo set to True
  end;

implementation

  constructor TLogger.Create();
  begin
    {$IFDEF Android}
      FilePath := TPath.GetDownloadsPath + System.SysUtils.PathDelim;
    {$ELSE}
      FilePath := ExtractFilePath(ParamStr(0));
    {$ENDIF}
    FileName := 'development.log';
    LDisplayInMemo := False;
    // inherited
    inherited Create;
  end;

  constructor TLogger.Create(LogFileName : String);
  begin
    {$IFDEF Android}
      FilePath := TPath.GetDownloadsPath + System.SysUtils.PathDelim;
      //TPath.Combine(TPath.GetDocumentsPath,'test.txt');  // to have / \ auto-change
    {$ELSE}
      FilePath := ExtractFilePath(ParamStr(0));
    {$ENDIF}
    FileName := LogFileName;
    LDisplayInMemo := False;
    // inherited
    inherited Create;
  end;

  destructor TLogger.Destroy();
  begin
    inherited Destroy;
  end;

  // adds a sigle line to log file with date time
  procedure TLogger.Log(LogString : String);
  begin
    NewLoggerThread :=  TLoggerThread.Create(True);
    NewLoggerThread.FreeOnTerminate := True;
    NewLoggerThread.Log := LogString;                                    //log to write - date time then added in execute
    NewLoggerThread.LoggerInstruction := TLoggerInstruction.liLogToFile; //set instuction for thread - LogToFile
    NewLoggerThread.FileName := FileName;  //file to write
    NewLoggerThread.FilePath := FilePath;  //path to file

    try
      NewLoggerThread.Start;
    except
      NewLoggerThread.Free();
    end;

  end;

  // results String with LogFile content
  procedure TLogger.GetLogsFromFile();
  begin
    NewLoggerThread :=  TLoggerThread.Create(True);
    NewLoggerThread.FreeOnTerminate := True;
    NewLoggerThread.OnTerminate := GetLogsFromFileThreadTerminateHandler;
    NewLoggerThread.FileName := FileName;  //file to write
    NewLoggerThread.FilePath := FilePath;  //path to file
    NewLoggerThread.LoggerInstruction := TLoggerInstruction.liGetLogsFromFile; //set instuction for thread - GetLogFromFile

    try
      NewLoggerThread.Start;
    except
      NewLoggerThread.Free();
    end;

  end;

  procedure TLogger.GetLogsFromFileThreadTerminateHandler(sender: TObject);
  begin
    LStringResult := (Sender as TLoggerThread).StringResult;
    if LDisplayInMemo then
        LLoggerMemo.Text := (Sender as TLoggerThread).StringResult;
  end;

end.

如您所见,只有LDisplayInMemo有所不同:如果为True,TMemo将填充日志...当为False时,我需要2次单击按钮4才能在TMemo中获得结果...

As you can see only difference is in LDisplayInMemo: if is True TMemo fills with logs... when is False I need 2 clicks on Button 4 to get results in TMemo...

  procedure TLogger.GetLogsFromFileThreadTerminateHandler(sender: TObject);
  begin
    LStringResult := (Sender as TLoggerThread).StringResult;
    if LDisplayInMemo then
        LLoggerMemo.Text := (Sender as TLoggerThread).StringResult;
  end;

有什么想法吗?老实说,我不知道这两种解决方案出现差异的原因是什么:(我还在Self.Memo1.Text:= logger.LogsResult;之后尝试了ProcessMessages.

Any ideas? To be honest I have no idea what's the reason of diffenerce in working of both solutions :( I also tried ProcessMessages after Self.Memo1.Text := logger.LogsResult;

推荐答案

以下代码仅在您第二次单击该按钮时才起作用的原因是,您实际上要获取日志信息的代码在另一个线程中运行... strong> 异步

The reason the following code only works the second time you click the button is that your code to actually get the log information runs in another thread... it's asynchronous!

logger.DisplayInMemo := False;
logger.GetLogsFromFile();
Self.Memo1.Text := logger.LogsResult; //This line runs AT THE SAME TIME you're getting logs!

注意:您正在读取logger.LogsResult 之前的值,该值是从LoggerThread获取值的.

NOTE: You're reading the value of logger.LogsResult before it gets a value from your LoggerThread.

再次单击该按钮时,线程已完成运行(第一次),现在您可以读取一个值.

When you click the button a second time, the thread has finished running (the first time), and you're now able to read a value.

您的注释部分起作用的原因是,您仅在线程终止时分配备忘录文本-即完成工作.

The reason your commented section works, is that you are only assigning the memo text when the thread terminates - i.e. finished doing it's work.

这篇关于Delphi XE5-需要奇怪的行为帮助的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆