2017-08-31 111 views
1

我使用下面的代码来设置属性使用RTTI与德尔福10.2东京在运行时创建的组件,一切正常,因为该示例的属性是TypeLine,因为我可以直接访问它。使用SetPropValue()和RTTI与德尔福东京更改组件属性

Componente_cc是可以与任何类实例化一个变量,无论是TLabelTButtonTEdit ......或任何其他。在这种情况下在下面,我将其实例化作为一个TLine.

Var 
    Componente_cc: TControl; 

    procedure TfrmPrincipal.AlteraPropriedades; 
    begin 
     if IsPublishedProp(Componente_cc, 'LineType') then 
      SetPropValue(Componente_cc, 'LineType', 'Diagonal'); 
    end; 

不过,我不明白怎么做时,有一个子属性,如Stroke,它具有KindColorCapDash等等。如何通过使用SetPropValue()函数来更改这些属性的值。为了更好地理解,我简化了示例代码,但在我的系统的一般环境中,我需要使用RTTI,当然直接通过代码更改属性会很简单,但我确实需要RTTI

回答

5

这与您的other RTTI issue类似,您可以通过RTTI访问控件的TextSettings.Font属性。同样的道理也适用于任何嵌套的属性,如Stroke.Color

对于每个嵌套子属性,你必须得到包含的对象,根据需要,直到达到所需的子对象,然后你重复可以根据需要获取/设置其属性值。

所以,在这种情况下,你必须使用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; 

注意,一个更强大的Enhanced RTTI德尔福2010年被引入(这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; 

但是,最好还是直接访问子属性,一旦你有机会获得更高级别的Ø bject,例如:

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; 
+0

你好@Remy,当你说有自2010年以来一个更强大的RTTI指的是你的第二个例子吗?直接访问属性? – Anderson

+0

我正在使用RTTI,因为它是我能找到的唯一解决方案,我的问题是所讨论的软件类似于IDE,用户添加控件并更改属性,调整大小等,因此组件正被添加到在运行时,他们可以是任何类,我试图做一个函数来添加所有类型的组件,另一个来获取属性,另一个来设置属性,所以我创建了TControl类型的对象,并在其中类,问题是在TControl我没有直接访问所有属性,所以我使用了RTTI。 – Anderson

+0

@Anderson:直接访问属性与RTTI无关,这只是普通的面向对象编程。 “PPropInfo”的使用并不新鲜,它始终可用。 'System.TypInfo'单元实现的旧式RTTI已被[System.Rtti'单元实现的增强RTTI(http://docwiki.embarcadero.com/RADStudio/en/Working_with_RTTI_Index)取代。 –