Delphi XE5-需要奇怪的行为帮助 [英] Delphi XE5 - strange behavior help needed
问题描述
我正在处理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屋!