In Delphi you can use RTTI (RunTime Type Information) to get information about objects at runtime without knowing about them at compile time. To find out more about RTTI, you should check out these articles by Robert Love.
I used the RTTI to make an observer, that informs me, whenever a specific property gets changed. It is far from being complete, there are a lot of TypeKinds that I didn't implement a compare for. The observer could also be extended to support multiple properties.
And how it is used:
Download is available here.
I used the RTTI to make an observer, that informs me, whenever a specific property gets changed. It is far from being complete, there are a lot of TypeKinds that I didn't implement a compare for. The observer could also be extended to support multiple properties.
uses
Rtti, Classes;
type
TProc = reference to procedure;
TPropertyObserver = class
private
fTerminated : boolean;
public
constructor Create(aInstance : TObject; aPropertyName : string; aOnChange : TProc);
procedure Terminate;
end;
implementation
uses
SysUtils, TypInfo;
{ TPropertyObserver }
constructor TPropertyObserver.Create(aInstance: TObject; aPropertyName: string; aOnChange : TProc);
begin
TThread.CreateAnonymousThread(procedure
var
ctx : TRttiContext;
t : TRttiType;
oldValue, curValue : TValue;
b : boolean;
p : TRttiProperty;
begin
ctx := TRttiContext.Create;
try
t := ctx.GetType(aInstance.ClassType);
p := t.GetProperty(aPropertyName);
oldValue := p.GetValue(aInstance);
while not fTerminated do
begin
curValue := p.GetValue(aInstance);
b := false;
case curValue.Kind of
tkInt64,
tkEnumeration,
tkInteger: b := oldValue.AsOrdinal = curValue.AsOrdinal;
tkWChar,
tkLString,
tkWString,
tkString,
tkUString,
tkChar: b := oldValue.AsString = curValue.AsString;
tkFloat: b := oldValue.AsExtended = curValue.AsExtended;
// Some of these should get a compare, too
tkUnknown: ;
tkSet: ;
tkClass: ;
tkMethod: ;
tkVariant: ;
tkArray: ;
tkRecord: ;
tkInterface: ;
tkDynArray: ;
tkClassRef: ;
tkPointer: ;
tkProcedure: ;
end;
if not b then
begin
aOnChange;
oldValue := curValue;
end;
sleep(10);
end;
finally
ctx.Free;
end;
end).Start;
end;
procedure TPropertyObserver.Terminate;
begin
fTerminated := true;
end;And how it is used:
procedure TForm1.FormCreate(Sender: TObject);
begin
fObserver := TPropertyObserver.Create(self,'Left',procedure
begin
TThread.Synchronize(TThread.CurrentThread,procedure // Changing the VCL has to be done in the main thread
begin
edit1.Text := IntToStr(self.Left);
end);
end);
end;Download is available here.