Windows表单字体问题第一部分

4
我有一些用户控件在一个Windows窗体中。我想知道以下几点:
  1. 如果我设置主窗体的Font属性,它的子控件会得到a)新Font的副本,还是b)对新Font的引用,还是c)什么都不会得到?

  2. 字体需要被释放吗?例如,我是否可以安全地执行以下代码?

    form.Font = new Font(...);

  3. 当父级(FormUserControl)被释放时,字体会自动被释放吗?

谢谢, Gilbert

Windows窗体字体问题-第二部分:http://stackoverflow.com/questions/5149220/windows-form-fonts-questions-part-2 - gilbertc
4个回答

4
  1. Font属性是.NET对象,Winforms缓存本地的Windows字体,因为创建它们的成本相当高。.NET包装器对象非常小。

  2. 是的,代码没问题,Font属性设置器已经处理了之前分配的字体的释放。

  3. 是的,它由UserControl处理释放,而UserControl则由其父级自动释放。


1
一些开发人员曾因此被抓住,因此这里的措辞应该不同:
  1. 当设置窗体的Font属性时,其子控件既不会得到System.Drawing.Font对象的副本,也不会得到引用。窗体创建一个非托管句柄。子控件通过订阅特定事件来获取该句柄。如果未设置控件的Font属性,则Font属性getter返回父级的Font。
  2. 当控件被处理时,分配给Font属性的Font对象不会被处理。因此,您可以创建单个Font对象并将其分配给多个动态创建/处理的控件。
- Slava
1
那是完全不同的答案。你应该发布它,这样当用户同意时,他们会投票支持它。 - Hans Passant

1
  1. 当主窗体的Font属性设置时,其子控件既不会得到System.Drawing.Font对象的深拷贝,也不会得到对其的引用。在赋值时,父窗体创建一个未托管的字体对象句柄。所有子控件都订阅了父窗体的FontChanged事件,因此它们有机会获取该句柄并在以后用于文本呈现。如果控件的Font属性未明确设置(或默认字体),则控件的Font属性getter返回父窗体的Font。
  2. Windows Forms对任何其他属性都按逻辑预期执行:当您将System.Drawing.Font对象分配给控件的Font属性时,先前分配的System.Drawing.Font对象会被终结并进行垃圾回收,如果应用程序中不再存在对它的引用,则可以安全地执行此操作。
  3. 当控件被处理或另一个System.Drawing.Font被分配给Font属性时,分配给控件的System.Drawing.Font对象不会被处理。因此,您可以安全地创建单个System.Drawing.Font对象并将其分配给动态创建和处理的多个控件。您也可以自由地定期创建多个字体并将它们分配给控件以创建一些视觉效果。内部未托管的字体句柄由Windows Forms管理。

孩子们通过什么机制获得这个句柄,考虑到绘图方法需要一个“Font”对象而不是GDI句柄,他们能做些什么? - supercat
字体属性设置器调用OnFontChanged虚拟方法。此方法在每个子控件上调用OnParentFontChanged虚拟方法。这是子对象获取句柄的方式。事实上,托管控件的绘制方法期望Font对象,而如果未设置控件的Font,则Font属性获取器提供父级的Font对象。但是一些控件是WIN32窗口的托管包装器,而默认情况下WIN32使用一个应该通过此句柄设置的字体来绘制窗口文本。 - Slava
MSDN 显示 ParentFontChanged 只需要一个 EventArgs 参数。我没有看到任何字体句柄。父对象公开了一个 Font 属性,但是子控件似乎无论是否有有效的句柄都能正常绘制。控件是否将字体句柄缓存到其他地方,或者普通的绘制例程每次绘制时都会创建和释放字体句柄,或者如果需要,它们会使用 Font 中的句柄并创建/释放临时字体句柄? - supercat
当您向本地窗口发送WM_SETFONT消息并将HFONT句柄指定为参数时,此字体将成为当前窗口的默认字体。我没有深入研究这个问题,但我认为Windows Forms也是这样做的。 - Slava

0
  1. 如果子窗体已经打开,则不会得到副本。
    • 稍微扩展一下:如果子窗体确实继承了父窗体的字体,我认为在窗口已经打开后更改父窗体的字体不会影响子窗体的字体。
  2. 垃圾回收器应该会处理它。
  3. 是的。

0
据我所知,控件的 Font 属性用于确定绘制控件时要使用的字体设置,但与该属性关联的 GDI 字体并未用于绘制。控件不会在分配给其 Font 属性的字体被处理后或甚至在分配之前就失效而感到困扰。该控件显然能够使用字体对象的某些隐藏方面来确定字体的适当属性,即使在处理后仍然可用,但我不知道它是否:
  1. 如果未处理,则使用提供的 Font 对象,否则每次必须绘制某些内容时都会创建自己的临时字体对象并立即处理临时对象。
  2. 如果未处理,则使用提供的 Font 对象,否则创建自己的私有字体对象,并在重新分配 Font 属性或处理控件时处理该对象。
  3. 在分配 Font 属性时从 Font 对象复制字体系列、大小等,并使用自己创建的私有临时或持久 Font 对象执行所有操作。
  4. 每当需要绘制某些内容时,从分配的 Font 对象中复制字体系列、大小等。
控件肯定会保留对传入的字体对象的引用,即使只是为了将其提供给Font属性的getter方法。但我不知道,是更好地在分配后释放字体,还是在窗体本身被释放时保留字体的副本并进行释放。

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