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.