Drarok
Drarok

Reputation: 3809

Dynamically access a property in a Delphi component

I'm using Delphi 5, and we have a method to dynamically create certain controls based on the contents of a database table (we create TButtons mostly) and take action when those are clicked. This allows us to add simple controls to a form without having to recompile the application.

I was wondering if it was possible to set a component's property based on a property name contained in a string so we could set further options.

Pseudo-code:

Comp := TButton.Create(Self);

// Something like this:
Comp.GetProperty('Left').AsInteger := 100;
// Or this:
Comp.SetProperty('Left', 100);

Is this possible at all?

Upvotes: 7

Views: 10077

Answers (3)

Daniel Rikowski
Daniel Rikowski

Reputation: 72504

You have to use the Run-Time Type Information features of Delphi to do this:

This blog describes exactly what you are trying to do: Run-Time Type Information In Delphi - Can It Do Anything For You?

Basically you have to get the property information, using GetPropInfo and then use SetOrdProp to set the value.

uses TypInfo;

var
  PropInfo: PPropInfo;
begin
  PropInfo := GetPropInfo(Comp.ClassInfo, 'Left');
  if Assigned(PropInfo) then
    SetOrdProp(Comp, PropInfo, 100);
end;

This is not as concise as your pseudo-code, but it still does the job. Also it gets more complicated with other stuff, like array properties.

Upvotes: 15

Shaun Roselt
Shaun Roselt

Reputation: 3242

Just as an added example. Here is how to set sub-properties, I'm setting the Margins on this Button component:

uses TypInfo;

...

procedure TForm1.Button1Click(Sender: TObject);
begin
  var PropInfo := GetPropInfo(Button1.ClassInfo, 'Margins');
  if Assigned(PropInfo) then
  begin
    var Margins := TMargins.Create(self);
    try
      Margins.Left := 100;
      Margins.Top := 100;
      Margins.Right := 100;
      Margins.Bottom := 100;
      SetObjectProp(Button1, PropInfo, Margins);
    finally
      Margins.Free;
    end;
  end;
end;

This works on Delphi 10.3 Rio and later due to the inline variables.

Upvotes: 0

Edelcom
Edelcom

Reputation: 5058

From one of my working units (in Delphi 7 though)

  var
     c : TComponent;

  for i := 0 to pgcProjectEdits.Pages[iPage].ControlCount - 1 do
  begin
     c := pgcProjectEdits.Pages[iPage].Controls[i];
     if c is TWinControl
     then begin
        if IsPublishedProp(c,'color')
        then
           SetPropValue(c,'color',clr);
        if IsPublishedProp(c,'readonly')                        
        then                                                    
           SetPropValue(c,'readonly', bReadOnly );  
        ...            
     end;
     ...

You have to include TypInfo in the uses statement. Don't know if this works under Delphi 5.

Upvotes: 10

Related Questions