如何检测一个TWinControl是否有FONT属性?

How to detect whether a TWinControl has a FONT property?

我需要更改通过容器控件的 Controls 属性 收集的控件的字体 属性:

for i := 0 to ContainerControl.ControlCount - 1 do
begin  
  ContainerControl.Controls[i].Font.Size := 8;  // error  
end;

为此,我需要将 ContainerControl.Controls[i] 类型转换为具有字体 属性 的 TWinControl class。有这样的class吗?或者如何检测特定的 TWinControl 是否具有 FONT 属性?或者我如何将特定的 TWincontrol 类型转换为特定的其他 TWinControl 的类型?

每个 TControl 都有一个字体属性,它只是受到保护。所以你可以使用 the usual cast trick:

type
  TControlAccess = class(TControl);

TControlAccess(MyControl).Font.Size := 10;

所有的可视化控件都有一个Font属性,但是在TControl层是protected,并不是所有的派生控件都会将它提升到published ].如果您只对具有 published Font 的控件感兴趣,那么您必须使用 RTTI 来测试它们,例如:

uses
  ..., TypInfo;

var
  Ctrl: TControl;
  i: Integer;
begin
  for i := 0 to ContainerControl.ControlCount - 1 do
  begin  
    Ctrl := ContainerControl.Controls[i];
    if IsPublishedProp(Ctrl, 'Font') then
      TFont(GetObjectProp(Ctrl, 'Font', TFont)).Size := 8;
  end;
end;

或者:

uses
  ..., TypInfo;

var
  Ctrl: TControl;
  Prop: PPropInfo;
  i: Integer;
begin
  for i := 0 to ContainerControl.ControlCount - 1 do
  begin  
    Ctrl := ContainerControl.Controls[i];
    Prop := GetPropInfo(Ctrl, 'Font', [tkClass]);
    if Prop <> nil then
      TFont(GetObjectProp(Ctrl, Prop, TFont)).Size := 8;
  end;
end;

或者,仅在 Delphi 2010 年及以后:

uses
  ..., System.Rtti;

var
  Ctrl: TControl;
  Ctx: TRttiContext;
  Prop: TRttiProperty;
  i: Integer;
begin
  Ctx := TRttiContext.Create;
  try
    for i := 0 to ContainerControl.ControlCount - 1 do
    begin  
      Ctrl := ContainerControl.Controls[i];
      Prop := Ctx.GetType(Ctrl.ClassType).GetProperty('Font');
      if (Prop <> nil) and (Prop.Visibility = TMemberVisibility.mvPublished) then
        TFont(Prop.GetValue(Ctrl).AsObject).Size := 8;
    end;
  finally
    Ctx.Free;
  end;
end;