5

を使用するカスタムコンポーネントがありますParentFont

コンポーネントの構築中に、最初はコンポーネントのフォントがデフォルトに設定されていることがわかりますMS Sans Serif

constructor TCustomWidget.Create(AOwner: TComponent);
begin
   inherited Create(AOwner);

   ...
end;

ショーの検査Self.Font.Name: 'MS Sans Serif'

しばらくして、コンポーネントのフォントが更新され、親のフォントが反映されます。

TReader.ReadComponent(nil)
   SetCompName
      TControl.SetParentComponent
         TControl.SetParent
            TWinControl.InsertControl
               AControl.Perform(CM_PARENTFONTCHANGED, 0, 0);

その後、すべてが素晴らしいものになり、コンポーネントのフォントが親のフォントに変更されました(例: `MS Shell Dlg 2')。

問題は、私の子コントロールが親のフォント(つまり私のコンポーネント)と同期していないことです。

コンポーネントコンストラクター中に、子コントロールを作成します。

constructor TCustomWidget.Create(AOwner: TComponent);
begin
   inherited Create(AOwner);

   ...
   CreateComponents;
end;

procedure TCustomWidget.CreateComponents;
begin
   ...
   FpnlBottom := TPanel.Create(Self);
   FpnlBottom.Caption := '';
   FpnlBottom.Parent := Self;
   FpnlBottom.Align := alBottom;
   FpnlBottom.Height := 46;
   FpnlBottom.ParentFont := True;
   ...
end;

そして、最初FpnlBottomはデフォルトのフォントもありMS Sans Serifます。

後で、コンポーネントのフォント親のフォントに更新された場合(たとえばMS Shell Dlg 2)、子コントロールのフォントは更新されず、残りMS Sans Serifます。

  • 子供のコントロールのParentFont所有物が尊重されないのはなぜですか?
  • ParentFont子コントロールのプロパティを機能させるにはどうすればよいですか?

サンプルコード

2時間ツールを使用して、管理可能で再現可能なコードに切り詰めます。

unit WinControl1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls;

type
    TWidget = class(TWinControl)
    private
        FTitleLabel: Tlabel;
        FpnlBottom: TPanel;

        procedure CreateComponents;
    protected
        procedure FontChange(Sender: TObject);
    public
        constructor Create(AOwner: TComponent); override;
    published
        {Inherited from TWinControl}
        property Align;
        property Font;
        property ParentFont;
    end;

    procedure Register;

implementation

procedure Register;
begin
    RegisterComponents('Samples',[TWidget]);
end;

{ TCustomWidget }

constructor TWidget.Create(AOwner: TComponent);
begin
    inherited Create(AOwner);

    ControlStyle := ControlStyle + [csAcceptsControls, csNoDesignVisible];

    Self.Width := 384;
    Self.Height := 240;

    Self.Font.OnChange := FontChange;

    CreateComponents;
end;

procedure TWidget.CreateComponents;
begin
    FpnlBottom := TPanel.Create(Self);
    FpnlBottom.Parent := Self;
    FpnlBottom.Align := alBottom;
    FpnlBottom.Color := clWindow;
    FpnlBottom.Caption := 'FpnlBottom';
    FpnlBottom.Height := 45;

    FTitleLabel := TLabel.Create(Self);
    FTitleLabel.Parent := FpnlBottom;
    FTitleLabel.Left := 11;
    FTitleLabel.Top := 11;
    FTitleLabel.Caption := 'Hello, world!';
    FTitleLabel.AutoSize := True;
    FTitleLabel.Font.Color := $00993300;
    FTitleLabel.Font.Size := Self.Font.Size+3;
    FTitleLabel.ParentFont := False;
end;

procedure TWidget.FontChange(Sender: TObject);
begin
    //title label is always 3 points larger than the rest of the content
    FTitleLabel.Font.Name := Self.Font.Name;
    FTitleLabel.Font.Size := Self.Font.Size+3;

    OutputDebugString(PChar('New font '+Self.Font.Name));
end;

end.
4

2 に答える 2

5

サンプルコードを見た後、FontChangeイベントハンドラーをすべて間違って使用しています。まったく使用しないでください。TControl.FontChanged()トリガーCM_FONTCHANGEDと通知を行うネイティブイベントハンドラーをバイパスしているため、実際にはロジックCM_PARENTFONTCHANGEDが壊れています。イベントハンドラーを完全ParentFontに削除するだけです。TWidget.FontChanged()コンポーネントのプロパティの変更に対応する必要がある場合は、代わりにメッセージFontをインターセプトする必要があります。例:CM_FONTCHANGED

unit WinControl1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls;

type
  TWidget = class(TWinControl)
  private
    FTitleLabel: TLabel;
    FpnlBottom: TPanel;
    procedure CreateComponents;
    procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
  public
    constructor Create(AOwner: TComponent); override;
  published
    {Inherited from TWinControl}
    property Align;
    property Font;
    property ParentFont;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Samples',[TWidget]);
end;

{ TCustomWidget }

constructor TWidget.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  ControlStyle := ControlStyle + [csAcceptsControls, csNoDesignVisible];
  Self.Width := 384;
  Self.Height := 240;
  CreateComponents;
end;

procedure TWidget.CreateComponents;
begin
  FpnlBottom := TPanel.Create(Self);
  FpnlBottom.Parent := Self;
  FpnlBottom.Align := alBottom;
  FpnlBottom.Color := clWindow;
  FpnlBottom.Caption := 'FpnlBottom';
  FpnlBottom.Height := 45;

  FTitleLabel := TLabel.Create(Self);
  FTitleLabel.Parent := FpnlBottom;
  FTitleLabel.Left := 11;
  FTitleLabel.Top := 11;
  FTitleLabel.Caption := 'Hello, world!';
  FTitleLabel.AutoSize := True;
  FTitleLabel.Font.Color := $00993300;
  FTitleLabel.Font.Size := Self.Font.Size+3;
  FTitleLabel.ParentFont := False;
end;

procedure TWidget.CMFontChanged(var Message: TMessage);
begin
  inherited; // let TControl and TWinControl react first
  //title label is always 3 points larger than the rest of the content
  FTitleLabel.Font.Name := Self.Font.Name;
  FTitleLabel.Font.Size := Self.Font.Size + 3;
  OutputDebugString(PChar('New font ' + Self.Font.Name));
end;

end. 
于 2011-02-14T22:29:21.960 に答える
4

コンポーネントのFontプロパティが更新されるたびに、コンポーネントはその子コントロールのそれぞれにメッセージを自動的に送信します。CM_PARENTFONTCHANGEDその時点で、各コントロールはそのParentFontプロパティがTrueであるかどうかをチェックします。ParentFont子コントロールのプロパティがまだTrueに設定されていることを確認しましたか?おそらく、独自のDFMストリーミング中に、子コントロールがFontプロパティを設定しているため、がFalseにリセットされParentFontます。

于 2011-02-14T22:14:19.937 に答える