-4

I need to change the FONT property of controls collected via the Controls property of a container control:

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

For this, I would need to typecast ContainerControl.Controls[i] to a class of TWinControl having a FONT property. Is there such a class? Or how can I detect whether a specific TWinControl has a FONT property? Or how cany I typecast a specific TWincontrol to the type of a specific other TWinControl?

user1580348
  • 5,721
  • 4
  • 43
  • 105
  • 1
    Why do you want to do this? If you have a windowed control with a lot of child controls, you can change the font of all children by simply changing the font of the parent. This works by default, since `ParentFont` is `True` by default. Otherwise, if you know you only have a small number of possible classes, you can do a plain boring `if Controls[i] is TEdit then TEdit(Controls[i]).Font.Name := 'Comic Sans MS' else if Controls[i] is TButton then...` – Andreas Rejbrand Feb 24 '20 at 16:45
  • For specific reasons which are too complex to explain here, I cannot use `ParentFont`. – user1580348 Feb 24 '20 at 16:57
  • You are mistaken. You can use ParentFont – David Heffernan Feb 24 '20 at 17:59
  • For specific reasons which are too complex to explain here, I cannot use ParentFont IN MY SPECIFIC CASE. For example, to restrict the controls to specific types to specific font changes. – user1580348 Feb 24 '20 at 18:14
  • 1
    if Assigned(GetPropInfo(ContainerControl.Controls[i], 'font')) then – Sertac Akyuz Feb 24 '20 at 19:01
  • 1
    Keep in mind that some controls may have more than 1 font property. Of course there's the main `Font` as noted, but may also have different elements that require separate font properties. For example, the `TChromeTabs` third-party control has numerous ones. – Jerry Dodge Feb 24 '20 at 20:00

2 Answers2

6

All visual controls have a Font property, but it is protected at the TControl layer, and not all derived controls promote it to published. If you are interested in only controls that have a published Font than you have to use RTTI to test them, eg:

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;

Alternatively:

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;

Alternatively, in Delphi 2010 and later only:

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;
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
2

Every TControl has a Font property, it's just protected. So you can use the usual cast trick:

type
  TControlAccess = class(TControl);

TControlAccess(MyControl).Font.Size := 10;
Uli Gerhardt
  • 13,748
  • 1
  • 45
  • 83