4
votes

I'm using Delphi's GetPropValue() function to get values ​​of certain properties of some objects of type TControl. Everything works correctly when I get simple property values ​​such as Value, Opacity, etc, but as I'm using firemonkey there are some extended properties, such as RotationCenter, it has RotationCenter.X and RotationCenter.Y, or even properties of text within TextSettings, in these properties with sub-types I can not get the values.

In this example I get the values ​​correctly:

If IsPublishedProp (Component_cc, 'Value') then
  EditValue.Text: = GetPropValue (Component_cc, 'Value', true);

Where Component_cc:TControl; And is created dynamically, it can also be any type of Firemonkey component (so far everything is okay, everything works).

When I need to use the form below, it does not work.

If IsPublishedProp (Component_cc, 'RotationCenter.X') then
  EditRotationCenterX.Text: = GetPropValue (CC_component, 'RotationCenter.X', true);

Does anyone know a way to get these properties extended by this function?

2
You need to go deeper in the structure. Ask for X property the TPosition object.Victoria

2 Answers

6
votes

First, the CC_component's RotationCenter property is actually an instance of TPosition class which decends from TPersistent.

Second, you cannot use dotted notation when calling IsPublishedProp.

You can use GetObjectProp to first retrieve the internal TPosition instance and then access the X property from there:

(Assume a simple FMX application with one form that contains a TButton called Button1 and a TEdit called EditRotationCenterX.)

procedure TForm1.Button1Click(Sender: TObject);

var
   CC_component : TComponent;
   CC_component_RotationCenter : TPosition;

begin
   CC_component := Button1;

   if IsPublishedProp(CC_component, 'RotationCenter') then
      begin
         CC_component_RotationCenter := TPosition(GetObjectProp(CC_component, 'RotationCenter'));
         EditRotationCenterX.Text := CC_component_RotationCenter.X.ToString;
      end
end;

Update, for a property of type Set:

For a Set type property, you will need to retrieve its ordinal value using GetOrdProp. This will be the array of bits that represent which elements are included in the current value. Then, you simply test if the appropriate bit is set. This is the method I would prefer.

Alternatively you can use GetSetProp which will return a text representation of the elements in the Set's current value. For example, if the Set's value is [TCorner.BottonLeft, TCorner.TopRight] the you will get back the string value "TopRight,BottonLeft". You then check to see if the name of your target element appears anywhere in the returned string. This method is susceptible to failure if the Delphi RTL or FMX libraries are ever changed in the future.

(This example adds a TRectangle shape called Rectangle1 and a TCheckBox called cbCornerBottonRight to the simple FMX App from above:)

procedure TForm1.Button1Click(Sender: TObject);

var
   CC_component : TComponent;
   CC_component_Corners : nativeint;

   CC_component_CornersAsString : string;

begin
   CC_component := Rectangle1;
   if IsPublishedProp(CC_component, 'Corners') then
      begin
         // Using this method will make your code less sensitive to 
         // changes in the ordinal values of the Set's members or      
         // changes to names of the enumeration elements.      
         //       
         CC_component_Corners := GetOrdProp(CC_component,'Corners');

         cbCornerBottonRight.IsChecked := ((1 shl ord(TCorner.BottomRight)) and CC_component_Corners) <> 0;


         // This approach may break if the names of the elements of
         // the TCorner enumeration are ever changed.  (BTW, they have
         // been in the past:  "cvTopLeft", "cvTopRight", "cvBottomLeft",
         // and "cvBottomRight" are now deprecated)
         //       
         CC_component_CornersAsString := GetSetProp(CC_component,'Corners');

         cbCornerBottonRight.IsChecked := CC_component_CornersAsString.IndexOf('BottomRight') >= 0;
      end;
end;
5
votes

When speaking about the old RTTI, you can do this. You need to go deeper in the structure. Ask for the X property the TPosition object:

var
  O: TObject;
  X: Integer;
begin
  if PropIsType(Component_cc, 'RotationCenter', tkClass) then
  begin
    O := GetObjectProp(Component_cc, 'RotationCenter');
    if Assigned(O) and PropIsType(O, 'X', tkInteger) then
      X := GetOrdProp(O, 'X');
  end;
end;