egnew 3 Posted March 22, 2023 I can set the property of a component on a form by value: SetPropValue(TopPanel,'align',alBottom); I want to be able to set the property using the name of the value as a string: SetPropValue(TopPanel,'align','alBottom'); How can this be accomplished? Thanks Share this post Link to post
programmerdelphi2k 237 Posted March 22, 2023 (edited) in fact, in RAD 11.3 " SetPropValue(Button1, 'Align', 'alRight'); " works... because the "variant" is accepted and internally is used as "tkEnumeration:" type. look at "procedure SetPropValue(Instance: TObject; PropInfo: PPropInfo; const Value: Variant);" in System.TypInfo.pas ---> SetEnumProp(Instance, PropInfo, VarToStr(Value)) --------> procedure SetEnumProp(Instance: TObject; PropInfo: PPropInfo; const Value: string); get the "name" of each value in TAlign and compare it.... if ok, result "Data := GetEnumValue(PropInfo^.PropType^, Value);" ------- edited ------ see "System.TypInfo.Set/GetVariantProp" + SetPropValue() usage! https://docwiki.embarcadero.com/Libraries/Sydney/en/System.TypInfo.SetVariantProp https://docwiki.embarcadero.com/Libraries/Sydney/en/System.TypInfo.GetVariantProp or look this https://stackoverflow.com/questions/45987321/change-component-properties-using-setpropvalue-and-rtti-with-delphi-tokyo Edited March 22, 2023 by programmerdelphi2k Share this post Link to post
egnew 3 Posted March 22, 2023 I checked the links you provided and do not yet see a solution. I can just use SetPropValue when the property is a simple type of sting, integer, float, etc. But here the property is a type. I am using Align as an example type, as it is a property of all TControl components: property Align: TAlign read FAlign write SetAlign default alNone; I dynamically create components at runtime using text commands and set the values of the components from the text. The command to create a panel aligned to TOP is "PANEL /ALIGN=TOP" which will be changed to "PANEL /ALIGN=alTOP" in the new version. Once I have this working, I can set any property in a component without knowledge of the component. In the current implementation, I have to deal with each property with a type using functions similar to this: function SetAlign(p_Control: TControl; p_Value: String); begin if SameText(p_Setting,'TOP') then p_Control.Align := alTop else if SameText(p_Setting,'BOTTOM') then p_Control.Align := alBottom etc... end; I validate a property name using this: function GetPropertyType(p_Component: TComponent; const p_PropertyName: String): String; var v_Context: TRttiContext; v_Property: TRttiProperty; begin v_Property := v_Context.GetType(p_Component.ClassType).GetProperty(p_PropertyName); Result := v_Property.PropertyType.ToString; end; I am attempting to resolve these problems: 1) How do I get the current value of the property? 2) How do I change the value of a property when the property is a type? That is the question posted here. 3) How do I validate the string that identifies the new property value? I can obtain valid strings for TAlign using the following: for I := Ord(Low(TAlign)) to Ord(High(TAlign)) do p_Memo.Lines.Add(GetEnumName(TypeInfo(TAlign),I)) However, I have not been able to determine how to do this for a type I don't know ahead of time using a parameter like: for I := Ord(Low(p_Type)) to Ord(High(p_Type)) do p_Memo.Lines.Add(GetEnumName(TypeInfo(p_Type),I)) Thanks Share this post Link to post
programmerdelphi2k 237 Posted March 22, 2023 (edited) 1) var LVal : variant := GetPropValue(Panel1, 'Align'); // get it value 2) will be this? {case} if VarType( LVal ) = varUString { varString, etc... } then SetPropValue(Button1, 'Align', string( LVal ) ); Edited March 22, 2023 by programmerdelphi2k Share this post Link to post
egnew 3 Posted March 22, 2023 Thanks very much. 1 - Works Perfectly 2 - Works Perfectly 3 - Any idea how to the names of the type values? I can do it as shown in my previous email by specifying the type. I need to do it from the type name instead. 4 - I used this code to get the property type. Is there a better way? function GetPropertyType(p_Component: TComponent; const p_PropertyName: String): String; var v_Context: TRttiContext; v_Property: TRttiProperty; begin v_Property := v_Context.GetType(p_Component.ClassType).GetProperty(p_PropertyName); Result := v_Property.PropertyType.ToString; end; Thanks Share this post Link to post
egnew 3 Posted March 22, 2023 3) Not a problem. I realized I didn't need the list of values. I can try the provided value. An "invalid property element: <value>" exception is returned. However, if you have a solution, that would be useful. Thanks again. Share this post Link to post
KodeZwerg 54 Posted March 23, 2023 Maybe this helps you as it helped me. That method looks if property is available and set it. uses TypInfo, Rtti; function SetProperty(const AControl: TControl; const AProperty: string; const AValue: TValue): Boolean; var LControl: TControl; LRttiContext: TRttiContext; LRttiProperty: TRttiProperty; begin Result := False; try LControl := AControl; LRttiProperty := LRttiContext.GetType(LControl.ClassType).GetProperty(AProperty); if ((LRttiProperty <> nil) and (LRttiProperty.Visibility in [mvPrivate, mvProtected, mvPublic, mvPublished])) then begin LRttiProperty.SetValue(LControl, AValue); Result := True; end; except end; end; and it can be used like: SetProperty(AControl, 'Caption', AValue); 1 Share this post Link to post
egnew 3 Posted April 9, 2023 KodeZwerg. I had a solution using just System.TypInfo, which works for all simple types. try SetPropValue(p_Component,p_PropertyName,p_PropertyValue); except ... But your version is better as it allows me to set all properties. Example: SetPropertyValue(TControl(MyFDConnection.Params),'UserName','MyUserName'); Thank you very much. Share this post Link to post