如何有效地让`ParentFont = False`子控件使用与父级相同的字体名称?

时间:2015-12-16 07:28:23

标签: delphi

大多数VCL控件都具有FontsParentFont属性。最好设置ParentFont = True,字体将遵循其父字体NameHeightColor。这在控件之间提供了统一的视觉效果。

但是,我们可能希望通过设置Font.Style = fsBold或对比Font.Color,但使用相同的Font.Name作为父级字体,使一个或两个控件与其他控件具有不同的外观。这样做会ParentFont = false。从这一点开始,更改父级的字体名称或大小将不会对这些控件的字体属性产生任何影响。

我认为这可能是VCL的设计。也许有人有更好的设计实践或经验来分享字体和ParentFont问题。

考虑我让用户为应用程序设置默认字体名称的情况。那些ParentFont = False控件不会相应更改。编码中的手动覆盖是可能的,但引入额外编码是一项繁琐的工作。

3 个答案:

答案 0 :(得分:3)

这是众所周知的VCL限制。

您可以使用ParentFont或自定义字体设置,在这种情况下,不会传播更改父级中的字体属性。

最好的方法是在任何地方使用ParentFont = true,并在表单的OnCreate事件中在运行时设置特定控件的自定义字体属性。当然,在这种情况下,您在设计时会丢失What You See Is What You Get,但您可以更好地控制表单的实际运行时外观。

procedure TForm1.OnCreate(Sender: TObject);
begin
  inherited;
  Label1.Font.Style := [fsBold];
  Label1.Font.Color := clRed;
end;

要应用用户自定义字体选择,您还需要重新创建表单,或在为特定控件应用自定义样式之前使用ParentFont := true,以便他们选择新的字体设置。

答案 1 :(得分:1)

我认为实现目标的最简单方法是在设计时不设置字体属性。到处使用ParentFont = True

然后在运行时进行您需要进行的任何修改。这允许您集中更改字体,并仍然让您的程序的其余部分选择它。

答案 2 :(得分:1)

可能的方法之一是注入后父母处理

只需检查TControl.CMParentFontChanged单元

中的VCL.Controls步骤

您还应该采用一些统一的方式为控件注入字体自定义。也许继承他们的WindowsProc或使用JediVCL中的EX控件等接口扩展标准控件

骨干 - 难以复制的概念证明 - 维护问题 - 如下所示。

unit xxx;
interface uses yyyy;

type 
 (*********** hijack start!  ****)

 TFontOverrideEvent = reference to procedure (const Sender: TObject; const Font: TFont);

 TButton = class( VCL.StdCtrls.TButton )
    protected 
       procedure ParentFontChanged(var m: TMessage); message CM_ParentFontChanged;
    public
       var FontOverrideEnabled: Boolean;
       var OnFontOverride: TFontOverrideEvent;
 end;

 (**** hijack end! standard form declaration below ****)

 TForm1 = class(TForm)
 ....
    Button1: TButton;
 ...
    procedure FormCreate(Sender: TObject);
  ...
implementation

procedure TForm1.FormCreate(Sender: TObject);
begin
  Button1.OnFontOverride :=
    procedure (const Sender: TObject; const LFont: TFont) begin
       with LFont do Style := [fsBold] + Style;
    end;
  Button1.FontOverrideEnabled := true;
  Button1.ParentFont := true;     

  PostMessage( Button1.Handle, CM_ParentFontChanged, 0, 0); 
  // trigger control to borrow font with customization
end;

....

 (*** hijack implementation ***)

procedure TButton.ParentFontChanged(var m: TMessage);
var SilenceHim1: IChangeNotifier; SilenceHim2: TNotifyEvent;
begin
  inherited; 
     // let VCL make standard font copying
     // warning! it may also make AutoSize or other automatic re-layout!
     // as we hide the fact of our font tuning from VCL - it would not 
     // have a chance to react to our customizations!

  if FontOverrideEnabled and Assigned( OnFontOverride ) then
  begin
    SilenceHim2 := Font.OnChange;
    SilenceHim1 := Font.FontAdapter; 
    try
      Font.OnChange := nil;
      Font.FontAdapter := nil;
      OnFontOverride( Self, Font );
    finally
      Font.OnChange := SilenceHim2;
      Font.FontAdapter := SilenceHim1;  
    end;
  end;
end;

然后在运行时尝试更改From1.Font并查看Button1如何将更改应用于自身