We help IT Professionals succeed at work.

How to set property via Variant?

perkley
perkley asked
on
Medium Priority
890 Views
Last Modified: 2010-04-06
I am trying to set properties that are known from a string.  For example: Label1.Caption := 'Hello World';

If I read from a Ini File "Label1" then I can do: FindComponent('Label1') and set the caption.  However, I am trying to set the property, so it would be something like this:

Label1.FindProperty('Caption') := 'Hello World';

Below is what I have found out that works for string properties, but I need to set any property.

For example: Label1.SetProperty('Font.Color') := clred;

So by looking at the working code below, can someone help me with doing it with any property value, not just string types.

Uses typinfo

procedure TForm1.setprop(AComp: TComponent; APropName, Value: string);
var
  TypeInf: PTypeInfo;
  PropInfo: PPropInfo;
begin
  TypeInf := AComp.ClassInfo;
  PropInfo := GetPropInfo(TypeInf, APropName);
  SetStrProp(AComp, PropInfo, Value);
end;

function TForm1.GetProp(AComp: TComponent; APropName: string):string;
var
  TypeInf: PTypeInfo;
  PropInfo: PPropInfo;
begin
  TypeInf := AComp.ClassInfo;
  PropInfo := GetPropInfo(TypeInf, APropName);
  Result := GetStrProp(AComp, PropInfo)
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  SetProp(Label1, 'Caption', GetProp(Button1, 'Caption'));
end;
Comment
Watch Question

Commented:
listening ... for moment
Commented:
You can use GetPropValue, SetPropValue from TypInfo unit.
However they don't work with subproperties (property path like 'Font.Color'), therefore

function GetProp(Instance: TObject; PropPath: PChar): Variant;
var
  PropName: string;
  PropInstance: TObject;
begin
  while PropPath^ <> #0 do
  begin
    if PropPath^ = '.' then
    begin
      PropInstance := TObject(GetOrdProp(Instance, PropName));
      Inc(PropPath);
      Result := GetPropValue(PropInstance, PropPath);
      Exit;
    end;
    PropName := PropName + PropPath^;
    Inc(PropPath);
  end;
  Result := GetPropValue(PropInstance, PropPath);
end;

function GetPropPathValue(Instance: TObject; const PropPath: string): Variant;
begin
  Result := GetProp(Instance, PChar(PropPath));
end;

procedure SetProp(Instance: TObject; PropPath: PChar; const Value: Variant);
var
  PropName: string;
  PropInstance: TObject;
begin
  while PropPath^ <> #0 do
  begin
    if PropPath^ = '.' then
    begin
      PropInstance := TObject(GetOrdProp(Instance, PropName));
      Inc(PropPath);
      SetProp(PropInstance, PropPath, Value);
      Exit;
    end;
    PropName := PropName + PropPath^;
    Inc(PropPath);
  end;
  SetPropValue(Instance, PropName, Value);
end;

procedure SetPropPathValue(Instance: TObject; const PropPath: string; const Value: Variant);
begin
  SetProp(Instance, PChar(PropPath), Value);
end;

examples:

// ordinal
SetPropPathValue(Label1, 'Font.Color', clRed);
// Boolean
SetPropPathValue(Self, 'HorzScrollBar.Visible', 'True');
// enumerated
SetPropPathValue(Self, 'HorzScrollBar.Style', 'ssFlat');
// set
SetPropPathValue(Label1, 'Anchors', '[akTop,akRight]');
// float
SetPropPathValue(DateTimePicker1, 'Date', Date + 1);
// string
SetPropPathValue(Label1, 'Caption', 'Hello, world!');

Note that SetPropValue does not support reference properties either but this will work:
// reference
SetOrdProp(Label2, 'FocusControl', Integer(Edit1));

// quick get test
ShowMessage(GetPropPathValue(Self, 'HorzScrollBar.Visible'));

HTH
TOndrej

Commented:
sorry, I've made a typo in GetProp :-( the last line should be:

Result := GetPropValue(Instance, PropPath); // not PropInstance

Author

Commented:
Thank you very much, this is exactly what I wanted (so far anyway).

Commented:
Glad to help :-)