2014-01-29 5 views
1

내 응용 프로그램 로그 파일에 로깅 TLogger 클래스에서 일하고 있어요 ...델파이 XE5는 이상한 행동 도움말

내가 잇는 TMemo에 파일에서 로그를 얻는 방식이 필요 그런 다음 TLogger 클래스에 DisplayInMemo 속성에 True를 할당 한 다음 GetLogFromFile()을 호출하십시오. 2. GetLogsFromFile()을 호출하십시오. 다음 Self.Memo1.Text : = TLogger.LogsResult; 솔루션은 잘 작동 아래 ... 댓글

는 ... 주석 솔루션은 버튼 만 매 2 클릭 작동 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 구현 :

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. 

만 차이는 볼 수 있듯이 LDesplayInMemo : True이면 TMemo가 로그로 채 웁니다 ... False 일 때 TMemo에서 결과를 얻으려면 버튼 4를 2 번 클릭해야합니다 ...

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를 시도했습니다.

답변

2

다음 코드는 두 번째로 만 작동하는 이유입니다. 버튼을 실제로 로그 정보를 얻을 수있는 코드가 다른 스레드에서 실행한다는 것입니다 클릭 ... 그건 비동기

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

참고 : 당신은 전에 logger.LogsResult의 값을 읽고 그 값 f를 얻는다. romger LoggerThread.

버튼을 두 번 클릭하면 스레드가 실행을 마치고 (처음) 값을 읽을 수 있습니다.

주석 처리 된 섹션이 작동하는 이유는 스레드가 종료 될 때 (즉 작업을 마치면)에만 메모 텍스트를 할당한다는 것입니다.