使用 SetPropValue() 和 RTTI with Delphi Tokyo 更改组件属性
Change component properties using SetPropValue() and RTTI with Delphi Tokyo
我使用下面的代码在运行时创建的组件中使用 RTTI
和 Delphi 10.2 Tokyo 设置属性,一切正常,因为示例的 属性 是TypeLine
,因为我可以直接访问。
Componente_cc
Is a variable that can be instantiated with any class, be it TLabel
, TButton
, TEdit
... or any other. In the case below I'm instantiating it as being a TLine.
Var
Componente_cc: TControl;
procedure TfrmPrincipal.AlteraPropriedades;
begin
if IsPublishedProp(Componente_cc, 'LineType') then
SetPropValue(Componente_cc, 'LineType', 'Diagonal');
end;
但是我没看懂当有子属性时怎么办,比如Stroke
,它有Kind
, Color
, Cap
, Dash
,等等。如何使用 SetPropValue()
函数更改这些属性的值。我已经简化了示例代码以便更好地理解,但是在我的系统的一般上下文中我将需要使用 RTTI
,当然直接通过代码更改属性会很简单,但我确实需要 RTTI
.
这类似于您的 ,您通过 RTTI 访问控件的 TextSettings.Font
属性。同样的事情适用于任何嵌套-属性,如Stroke.Color
,等等
对于每个嵌套的子属性,你必须得到包含的对象,根据需要重复直到你到达所需的子对象,然后你可以get/set 根据需要其 属性 值。
因此,在这种情况下,您必须使用 GetObjectProp()
来获取 Stroke
属性 对象,然后您可以使用 SetPropValue()
来设置该对象的属性。例如:
uses
..., TypInfo;
var
Componente_cc: TControl;
procedure TfrmPrincipal.AlteraPropriedades;
var
Stroke: TObject;
begin
if IsPublishedProp(Componente_cc, 'Stroke') then
begin
Stroke := GetObjectProp(Componente_cc, 'Stroke');
if Stroke <> nil then
SetPropValue(Stroke, 'Color', ...);
end;
end;
或者,为了避免对指定的 属性 进行双重 RTTI 查找:
uses
..., TypInfo;
var
Componente_cc: TControl;
procedure TfrmPrincipal.AlteraPropriedades;
var
PropInfo: PPropInfo;
Stroke: TObject;
begin
PropInfo := GetPropInfo(Componente_cc, 'Stroke', [tkClass]);
if PropInfo <> nil then
begin
Stroke := GetObjectProp(Componente_cc, PropInfo);
if Stroke <> nil then
SetPropValue(Stroke, 'Color', ...);
end;
end;
请注意,Delphi 2010 年引入了更强大的 Enhanced RTTI(此 RTTI 不仅限于已发布的属性,就像旧式 RTTI 一样),例如:
uses
..., System.Rtti;
var
Componente_cc: TControl;
procedure TfrmPrincipal.AlteraPropriedades;
var
Ctx: TRttiContext;
Prop: TRttiProperty;
Stroke: TObject;
begin
Ctx := TRttiContext.Create;
Prop := Ctx.GetType(Componente_cc.ClassType).GetProperty('Stroke');
if (Prop <> nil) and (Prop.PropertyType.TypeKind = tkClass) {and (Prop.Visibility = mvPublished)} then
begin
Stroke := Prop.GetValue(Componente_cc).AsObject;
if Stroke <> nil then
begin
Prop := Ctx.GetType(Stroke.ClassType).GetProperty('Color');
if (Prop <> nil) {and (Prop.Visibility = mvPublished)} then
Prop.SetValue(Stroke, ...);
end;
end;
end;
但是,最好在访问更高级别的对象后直接访问子属性,例如:
uses
..., TypInfo;
var
Componente_cc: TControl;
procedure TfrmPrincipal.AlteraPropriedades;
var
PropInfo: PPropInfo;
Stroke: TStrokeBrush;
begin
PropInfo := GetPropInfo(Componente_cc, 'Stroke', [tkClass]);
if PropInfo <> nil then
begin
Stroke := GetObjectProp(Componente_cc, PropInfo, TStrokeBrush) as TStrokeBrush;
if Stroke <> nil then
Stroke.Color := ...; // <-- no RTTI needed!
end;
end;
或者:
uses
..., System.Rtti;
var
Componente_cc: TControl;
procedure TfrmPrincipal.AlteraPropriedades;
var
Ctx: TRttiContext;
Prop: TRttiProperty;
Stroke: TStrokeBrush;
begin
Ctx := TRttiContext.Create;
Prop := Ctx.GetType(Componente_cc.ClassType).GetProperty('Stroke');
if (Prop <> nil) and (Prop.PropertyType.TypeKind = tkClass) {and (Prop.Visibility = mvPublished)} then
begin
Stroke := Prop.GetValue(Componente_cc).AsObject as TStrokeBrush;
if Stroke <> nil then
Stroke.Color := ...; // <-- no RTTI needed!
end;
end;
我使用下面的代码在运行时创建的组件中使用 RTTI
和 Delphi 10.2 Tokyo 设置属性,一切正常,因为示例的 属性 是TypeLine
,因为我可以直接访问。
Componente_cc
Is a variable that can be instantiated with any class, be itTLabel
,TButton
,TEdit
... or any other. In the case below I'm instantiating it as being aTLine.
Var
Componente_cc: TControl;
procedure TfrmPrincipal.AlteraPropriedades;
begin
if IsPublishedProp(Componente_cc, 'LineType') then
SetPropValue(Componente_cc, 'LineType', 'Diagonal');
end;
但是我没看懂当有子属性时怎么办,比如Stroke
,它有Kind
, Color
, Cap
, Dash
,等等。如何使用 SetPropValue()
函数更改这些属性的值。我已经简化了示例代码以便更好地理解,但是在我的系统的一般上下文中我将需要使用 RTTI
,当然直接通过代码更改属性会很简单,但我确实需要 RTTI
.
这类似于您的 TextSettings.Font
属性。同样的事情适用于任何嵌套-属性,如Stroke.Color
,等等
对于每个嵌套的子属性,你必须得到包含的对象,根据需要重复直到你到达所需的子对象,然后你可以get/set 根据需要其 属性 值。
因此,在这种情况下,您必须使用 GetObjectProp()
来获取 Stroke
属性 对象,然后您可以使用 SetPropValue()
来设置该对象的属性。例如:
uses
..., TypInfo;
var
Componente_cc: TControl;
procedure TfrmPrincipal.AlteraPropriedades;
var
Stroke: TObject;
begin
if IsPublishedProp(Componente_cc, 'Stroke') then
begin
Stroke := GetObjectProp(Componente_cc, 'Stroke');
if Stroke <> nil then
SetPropValue(Stroke, 'Color', ...);
end;
end;
或者,为了避免对指定的 属性 进行双重 RTTI 查找:
uses
..., TypInfo;
var
Componente_cc: TControl;
procedure TfrmPrincipal.AlteraPropriedades;
var
PropInfo: PPropInfo;
Stroke: TObject;
begin
PropInfo := GetPropInfo(Componente_cc, 'Stroke', [tkClass]);
if PropInfo <> nil then
begin
Stroke := GetObjectProp(Componente_cc, PropInfo);
if Stroke <> nil then
SetPropValue(Stroke, 'Color', ...);
end;
end;
请注意,Delphi 2010 年引入了更强大的 Enhanced RTTI(此 RTTI 不仅限于已发布的属性,就像旧式 RTTI 一样),例如:
uses
..., System.Rtti;
var
Componente_cc: TControl;
procedure TfrmPrincipal.AlteraPropriedades;
var
Ctx: TRttiContext;
Prop: TRttiProperty;
Stroke: TObject;
begin
Ctx := TRttiContext.Create;
Prop := Ctx.GetType(Componente_cc.ClassType).GetProperty('Stroke');
if (Prop <> nil) and (Prop.PropertyType.TypeKind = tkClass) {and (Prop.Visibility = mvPublished)} then
begin
Stroke := Prop.GetValue(Componente_cc).AsObject;
if Stroke <> nil then
begin
Prop := Ctx.GetType(Stroke.ClassType).GetProperty('Color');
if (Prop <> nil) {and (Prop.Visibility = mvPublished)} then
Prop.SetValue(Stroke, ...);
end;
end;
end;
但是,最好在访问更高级别的对象后直接访问子属性,例如:
uses
..., TypInfo;
var
Componente_cc: TControl;
procedure TfrmPrincipal.AlteraPropriedades;
var
PropInfo: PPropInfo;
Stroke: TStrokeBrush;
begin
PropInfo := GetPropInfo(Componente_cc, 'Stroke', [tkClass]);
if PropInfo <> nil then
begin
Stroke := GetObjectProp(Componente_cc, PropInfo, TStrokeBrush) as TStrokeBrush;
if Stroke <> nil then
Stroke.Color := ...; // <-- no RTTI needed!
end;
end;
或者:
uses
..., System.Rtti;
var
Componente_cc: TControl;
procedure TfrmPrincipal.AlteraPropriedades;
var
Ctx: TRttiContext;
Prop: TRttiProperty;
Stroke: TStrokeBrush;
begin
Ctx := TRttiContext.Create;
Prop := Ctx.GetType(Componente_cc.ClassType).GetProperty('Stroke');
if (Prop <> nil) and (Prop.PropertyType.TypeKind = tkClass) {and (Prop.Visibility = mvPublished)} then
begin
Stroke := Prop.GetValue(Componente_cc).AsObject as TStrokeBrush;
if Stroke <> nil then
Stroke.Color := ...; // <-- no RTTI needed!
end;
end;