Delphi组件:如何使用父字体?
我有一个使用 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.
i have a custom component that uses the ParentFont
.
During construction of my component, i can see that initially the component's font is set to the default MS Sans Serif
:
constructor TCustomWidget.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
...
end;
Inspecting shows Self.Font.Name: 'MS Sans Serif'
Some time later, the font of my component is updated to reflect the parent's font:
TReader.ReadComponent(nil)
SetCompName
TControl.SetParentComponent
TControl.SetParent
TWinControl.InsertControl
AControl.Perform(CM_PARENTFONTCHANGED, 0, 0);
And after that everything is great, my component's font has been changed to the parent's font (e.g. `MS Shell Dlg 2').
The problem is that my child controls are not keeping in sync with their parent's font (i.e. my component).
During my components constructor, i create child controls:
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;
And initially my FpnlBottom
has the default font also MS Sans Serif
.
Later, when the font of my component has been updated to its parent's font (e.g. MS Shell Dlg 2
), the child controls are not having their fonts updated, and are remaining MS Sans Serif
.
- Why are my child control's
ParentFont
property not being honored? - How do i make my child control's
ParentFont
property work?
Sample Code
Tool two hours to trim it down to manageable, reproducible, code:
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
查看示例代码后,您使用的
FontChange
事件处理程序完全错误。您根本不应该使用它。您正在绕过本机TControl.FontChanged()
事件处理程序,该处理程序会触发CM_FONTCHANGED
和CM_PARENTFONTCHANGED
通知,因此您实际上破坏了ParentFont
逻辑。只需完全删除TWidget.FontChanged()
事件处理程序即可。如果您需要对组件的Font
属性的更改做出反应,则需要拦截CM_FONTCHANGED
消息,例如:After seeing your sample code, you are using the
FontChange
event handler all wrong. You should not be using it at all. You are bypassing the nativeTControl.FontChanged()
event handler, which triggersCM_FONTCHANGED
andCM_PARENTFONTCHANGED
notifications, so you are actually breaking theParentFont
logic. Just get rid of yourTWidget.FontChanged()
event handler altogether. If you need to react to changed to your component'sFont
property, you need to intercept theCM_FONTCHANGED
message instead, eg:每次更新组件的
Font
属性时,组件都会自动向其每个子控件发送CM_PARENTFONTCHANGED
消息,此时每个控件都会检查其ParentFont
code> 属性是否为 True。您是否检查过以确保子控件的ParentFont
属性仍设置为 True?也许在它们自己的 DFM 流期间,子控件正在设置它们的Font
属性,这会将ParentFont
重置为 False。Every time your component's
Font
property is updated, the component automatically sendsCM_PARENTFONTCHANGED
messages to each of its child controls, at which time each control checks whether itsParentFont
property is True or not. Have you checked to make sure your child control'sParentFont
properties are still set to True? Perhaps during their own DFM streaming, the child controls are setting theirFont
properties, which wouuld reset theParentFont
to False.