A:
The screen resolution topic shows one way. Here is another example:
Uses TypInfo;
Function AssignFontProperty( anObj: TObject; Const fname: String ):
Boolean;
Var
PInfo: PPropInfo;
aFont: TFont;
FontGet: Function( anObj: TObject ): TFont;
Begin
(* try to get a pointer to the property information for a property
with the
passed name. TObject.ClassInfo returns a pointer
to the RTTI table, which
we need to pass to GetPropInfo *)
PInfo := GetPropInfo( anObj.ClassInfo, 'font' );
Result := PInfo <> Nil;
If result Then
(* found a property with this name, check if it
has the correct type *)
If (PInfo^.Proptype^.Kind = tkClass) and
GetTypeData(PInfo^.Proptype)^.ClassType.InheritsFrom(TFont)
Then Begin
{ try to get the read proc for this
property }
@FontGet:= PInfo^.GetProc;
If Assigned( FontGet ) and (PtrRec(PInfo^.GetProc).Seg
<> $FFFF) Then
{ hiword of $FFFF seems
to signify a property wich reads directly
from a field
instead of via a method! }
Begin
aFont := FontGet( anObj
);
If aFont Is TFont Then
aFont.Name :=
fname
Else
ShowMessage('FontGet
barfed');
End
Else Begin
{ no read method for the
property, get field directly }
aFont := TFont(GetOrdProp(
anObj, PInfo ));
If aFont Is TFont Then
aFont.Name :=
fname
Else
ShowMessage('GetOrdProp
barfed');
End;
End
Else Begin
(* nope, wrong type, complain *)
Result := False;
ShowMessage( 'Property Font is not of
type TFont!');
End;
End;
procedure TForm1.BtnTestClick(Sender: TObject);
Var
i: Integer;
begin
For i:= 0 To ComponentCount-1 Do
AssignFontProperty( Components[i], 'Symbol' );
end;
Put a few controls on your form, assign the BtnTestClick handler to a buttons OnClick property, run the app, click on the button and all will be greek to you <g>.
Here is a tip or two on using this information:
You already know which properties that one has in most cases. So it would only be a useful method in a base class of a class hierarchy (e.g. in TObject, which you cannot modify). A function that only looks for a property by name would require only one line of code:
Function HasProperty( anObj: TObject; Const name: String ): Boolean;
Begin
Result := GetPropInfo( anObj.ClassInfo, name ) <> Nil;
End;
But that is not very useful, it still does not solve the problem of how to _use_ the property!
Var
aComponent: TComponent;
i: Integer;
begin
For i:= 0 To ComponentCount-1 Do Begin
aComponent := Components[i];
If HasProperty( aComponent, 'Font' ) Then
aComponent.Font.Name := ....
<== will not compile
You still would need to cast aComponent to a class that has Font as
public or published property and of course it better be one that is in
the ancestry of aComponent. Using the run-time type info for the access
solves this problem but is a bit awkward as you saw.