unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
ComCtrls, ExtCtrls, EditBtn, Spin;
type
{ TMyThread }
TMyThread = class(TThread)
private
FLastFileAge: Integer;
FLogMessage: string;
FSleepEvent: PRTLEvent;
procedure Log(AValue: string);
public
MonitorInterval: Integer;
procedure SetFileAge(AValue: Integer);
procedure DoLog; //Dispatch method
function CheckFileChange: Boolean;
function UpdateDatabase: Boolean;
procedure Execute; override;
procedure WakeUp;
constructor Create({%H-}CreateSuspended: Boolean; const {%H-}StackSize: SizeUInt=DefaultStackSize);
end;
{ TForm1 }
TForm1 = class(TForm)
btnMonitor: TButton;
FileToCheck: TFileNameEdit;
Label1: TLabel;
Label2: TLabel;
lblInterval: TLabel;
lbLog: TListBox;
spinInterval: TSpinEdit;
procedure btnMonitorClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
Thread: TMyThread;
public
procedure LogMessage(AValue: string);
end;
var
Form1: TForm1;
implementation
{$R *.lfm}
{ TMyThread }
procedure TMyThread.Log(AValue: string);
begin
FLogMessage:=AValue;
Synchronize(@DoLog); //Dispatch methods called by synchronize take no arguments
end;
procedure TMyThread.SetFileAge(AValue: Integer);
begin
FLastFileAge:= AValue;
end;
procedure TMyThread.DoLog;
begin
Form1.LogMessage(FLogMessage);
end;
function TMyThread.CheckFileChange: Boolean;
begin
Result:=False;
if FLastFileAge = FileAge(Form1.FileToCheck.FileName) then
begin
Log(TimeToStr(Now) + ': File not changed');
end
else
begin
FLastFileAge:= FileAge(Form1.FileToCheck.FileName);
Log(TimeToStr(Now) + ': File changed');
end
end;
function TMyThread.UpdateDatabase: Boolean;
begin
//Process file and update database here..
Result:=False;
Log(TimeToStr(Now) + ': Database updated');
end;
procedure TMyThread.Execute;
begin
while not Terminated do
begin
if CheckFileChange then
UpdateDatabase;
RTLeventWaitFor(FSleepEvent, MonitorInterval);
end;
RTLeventdestroy(FSleepEvent);
Log(TimeToStr(Now) + ': Monitoring stopped');
end;
procedure TMyThread.WakeUp;
begin
RTLeventSetEvent(FSleepEvent);
end;
constructor TMyThread.Create(CreateSuspended: Boolean; const StackSize: SizeUInt);
begin
Inherited Create(True);
FSleepEvent:= RTLEventCreate;
end;
{ TForm1 }
procedure TForm1.btnMonitorClick(Sender: TObject);
begin
if btnMonitor.Caption='Start Monitoring' then
begin
if Trim(FileToCheck.FileName) = '' then
begin
ShowMessage('Please select a file to monitor!');
btnMonitorClick(nil); //Pauses the timer and updates the button
Exit;
end;
if not FileExists(FileToCheck.FileName) then
begin
ShowMessage(FileToCheck.FileName +' does not exist');
btnMonitorClick(nil); //Pauses the timer and updates the button
Exit;
end;
btnMonitor.Enabled:=False;
btnMonitor.Caption:='Stop Monitoring';
spinInterval.Enabled:= not spinInterval.Enabled;
FileToCheck.Enabled:= not FileToCheck.Enabled;
Thread:= TMyThread.Create(True);
Thread.MonitorInterval:=spinInterval.Value * 1000;
Thread.SetFileAge(FileAge(FileToCheck.FileName));
Thread.FreeOnTerminate:=True;
Thread.Start;
btnMonitor.Enabled:=True;
btnMonitor.Font.Color:=clRed;
end
else
begin
btnMonitor.Enabled:=False;
btnMonitor.Caption:='Start Monitoring';
Thread.Terminate; //Signal thread to finish
Thread.WakeUp; //Sets the FSleepEvent, thread wakes up, finds that
//it is terminated and self destructs
Thread.WaitFor; //Wait for thread to finish
btnMonitor.Enabled:=True;
spinInterval.Enabled:= not spinInterval.Enabled;
FileToCheck.Enabled:= not FileToCheck.Enabled;
btnMonitor.Font.Color:=clGreen;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
FileToCheck.FileName:= Application.Location + 'data.dat';
end;
procedure TForm1.LogMessage(AValue: string);
begin
{ Callback, called from thread }
lbLog.Items.Add(AValue);
lbLog.ItemIndex:=lbLog.Count -1;
end;
end.