整个项目中字体的一致性?

24

有没有一种快速有效的方法来应用全局字体,使其在整个项目中使用?

我的意思是我想设置一个特定的字体名称,所有控件都将使用该字体名称,例如 TButtonTEditTLabel等。

通常情况下,将表单的字体设置为特定控件的字体将更改该表单上的所有控件以指定的字体。

但这里有一个小问题,如果您手动更改了特定控件上的字体,则通过表单设置字体将不再更新那些已经手动更改过的控件的字体。

想法 1

我考虑使用 For 循环遍历我的表单上的每个组件,并以这种方式设置字体:

procedure TForm1.FormCreate(Sender: TObject);
var
  i: Integer;
begin
  with TForm(Self) do
  begin
    for i := 0 to ComponentCount - 1 do
    begin
      if Components[i] is TButton then
      begin
        TButton(Components[i]).Font.Name  := 'MS Sans Serif';
        TButton(Components[i]).Font.Size  := 8;
        TButton(Components[i]).Font.Style := [fsBold];
      end;

      if Components[i] is TLabel then
      begin
        TLabel(Components[i]).Font.Name  := 'MS Sans Serif';
        TLabel(Components[i]).Font.Size  := 8;
        TLabel(Components[i]).Font.Style := [fsBold];
      end;
    end;
  end;
end;

但这样做似乎很混乱,对于一个简单的任务来说需要写相当数量的代码。

想法2

我知道我可以手动为每个控件逐个更改设计时的字体,但是如果有几个表格要经过这个过程可能需要花费一些时间,即使这样我也可能会错过某个控件。

想法3

与想法2类似,另一种方法是将表单视为文本(DFM),然后通过查找和替换方式更改字体。


基本上,我正在追求应用程序的一致性,并且希望在整个应用中使用同一种字体。

我是否完全忽略了一些显而易见的事情?我所尝试做的是否过于复杂了?


7
如果您手动更改控件的字体,那么也会将其ParentFont属性设置为False; 将其设置为True以返回默认(父级)字体。 - kludg
11
在创建任何窗体之前,设置Application.DefaultFont.Name := 'MS Sans Serif';,并像Serg指出的那样在窗体中将ParentFont设置为true。要设置消息对话框中的字体,请设置Screen.MessageFont.Name属性。 - LU RD
1
如果您需要在运行时执行此操作,可以像上面一样迭代表单组件,并使用TypInfo单元中的IsPublishedProp(Components[i], 'Font')方法检查哪些组件已发布了Font属性。然后,您可以通过修改TControl来设置组件的Font属性。 - Max Williams
5
如果你从你的.dfm文件中去除了所有字体(Font)和父级字体(ParentFont)属性,则父级字体会默认为True,一切都很好。 - David Heffernan
1
@DavidHeffernan 那是另一个好提示 :) - user1175743
显示剩余2条评论
3个回答

27

如评论中所讨论的那样,这关键在于ParentFont属性。该属性在VCL层级结构的各个点上定义。如果您将ParentFont设置为链中所有组件的True,那么您只需修改一个字体即可更改整个应用程序的字体。

Application.DefaultFont
默认情况下,大多数组件会将ParentFont设置为True,所以您无需做任何操作。然而,有一个例外,即TForm。全新的默认表单将ParentFont设置为False。这有些令人失望,但我认为这反映了VCL的原始设计者没有预见到这一点,并且相对较晚地在VCL的开发中添加了ParentFont
不过没关系,在理想的情况下,应用程序中的所有窗体都应该派生自您控制的一个通用基类。如果是这样,那么您可以在那里简单地进行更改,将ParentFont设置为True,确保没有向窗体上的任何组件应用明确的字体设置,这样您就没有问题了。通过单个属性控制整个应用程序的字体。如果您的窗体没有通用的基类,那么现在是添加它的理想时机。如果您不想这样做,那么您需要为每个窗体设置ParentFont
其他相关属性是Screen.MessageFontScreen.MenuFont。它们提供了对消息框和菜单中使用的字体的全局控制。然而,Delphi的最新版本已经将绘制消息框和菜单的控制权还给了Windows,因此这些属性没有任何效果。

12
请记住,VCL窗体不像Swing(Java)或WPF(C#/.net)那样进行“布局管理”,在运行时更改字体会导致字体剪裁的问题,使您的用户界面变得难以阅读。祝好运。没有实用的方法可以更改应用程序的字体而无需手动逐个窗体地检查可读性。 - Warren P
3
@Warren,你说得很好,我本打算在我的回答中提到它,但是忘记了。在我的应用程序中,我使用Tahoma 8作为XP的字体或Segoe UI 9作为Vista+的字体显示。这需要调用ChangeScale来改变窗体布局。但是,你必须检查两种变体的窗体。只要不把标签挤在一起,就没有问题。ParentFont在所有这些方面都非常出色。 - David Heffernan
4
我打算亲自尝试这个,然后可能会在博客上写关于结果的文章。 - Warren P
3
+1 表示支持,“在您的应用程序中所有表单应派生自由控制的共同基类”。 - kobik
有没有一种方法可以在设计时设置 Application.DefaultFont - Fabrizio
显示剩余6条评论

2
关键是确保所有表格都来自于您自己的应用程序基本表格,如前所述。
然后,您可以查看每个表格和按钮等,并审查属性,其中任何修改过的字体属性都应该以粗体显示,并且很容易识别。大多数属性都有一个“恢复为继承”的菜单选项。这应该可以撤消任何先前的选择,无需转到文本版本进行编辑。(尽管它可能会完全删除由先前设置字体而导致的任何文本输入)。
我肯定希望修复每个表格,而不是将其定义错误并添加更多的代码来在运行时修复它。如果稍后决定做一些不同的事情,这种更改将给您带来更糟糕的问题。

1
如果您想在运行时执行此操作,就像您在Idea 1中描述的那样,您应该考虑将其制作成递归函数,如下所示:
procedure SetFontProperties(Control: TControl; Name: TFontName; Size: Integer; Styles: TFontStyles);
// Set font properties
var
  Index: Integer;
  Font: TFont;
  AnObject: TObject;
  ChildControl: TControl;
begin
  // Set font properties
  AnObject := GetObjectProp(Control, 'Font', nil);
  if AnObject is TFont then
  begin
    // Set properties
    Font := TFont(AnObject);
    Font.Name  := Name;
    Font.Size  := Size;
    Font.Style := Styles;
  end;

  // Set child font properties
  if Control is TWinControl then
  begin
    // Set
    for Index := 0 to TWinControl(Control).ControlCount - 1 do
    begin
      // Child control
      ChildControl := TWinControl(Control).Controls[Index];

      // Set font properties
      SetFontProperties(ChildControl, Name, Size, Styles);
    end;
  end;
end;

您可以通过以下方式为表单中的所有控件切换字体:

SetFontProperties(Self, 'Courier', 14, []);

该函数将设置表单的字体属性以及表单上所有子控件的字体属性,包括嵌套在TPanels或其他容器控件中的控件。

然而,我同意你的看法,这种方法有点凌乱。


编写这样的代码并不理想,但是你的答案仍然很有用 :) - user1175743
@MarjanVenema 这只是一个例子。如果您使用非VCL组件部署其他字体属性名称,则当然必须扩展该函数以包含这些属性名称。但是,讨论中的主要观点是Warren P在上面的评论中提到的观点:通常不可行像这样在运行时更改字体属性,因为它会改变对齐方式,引入字体剪切等问题。 - bjaastad_e

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接