Delphi Component: Как использовать родительский шрифт? - PullRequest
5 голосов
/ 14 февраля 2011

У меня есть пользовательский компонент, который использует 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 моего дочернего элемента управления?

Пример кода

Инструмент два часа, чтобы урезать его до управляемого, воспроизводимого, код:

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.

Ответы [ 2 ]

5 голосов
/ 15 февраля 2011

После просмотра вашего примера кода вы используете неправильный обработчик события 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. 
4 голосов
/ 15 февраля 2011

Каждый раз, когда свойство Font вашего компонента обновляется, компонент автоматически отправляет CM_PARENTFONTCHANGED сообщения каждому из его дочерних элементов управления, в это время каждый элемент управления проверяет, является ли его свойство ParentFont Истиной или нет.Вы проверили, чтобы убедиться, что свойства ParentFont вашего дочернего элемента управления все еще установлены в True?Возможно, во время их собственной потоковой передачи DFM дочерние элементы управления устанавливают свои свойства Font, что приведет к сбросу ParentFont в значение False.

...