Windows表单应用程序的默认字体

43
每当我创建一个新表单时,我的应用程序默认使用“Microsoft Sans Serif, 8.25pt”字体。 我没有更改它,因为我知道在这种情况下,我的表单应该采用系统的默认字体。 但是,当我运行我的应用程序时,使用的字体仍然不是Segoe UI(我的Windows Vista操作系统中的默认系统字体)。
为什么会发生这种情况?如何确保我的应用程序看起来像普通的Windows应用程序?

2
这是一个非常老的问题,但我想知道答案今天是否仍然适用。假设一个人在Windows 10上开发WinForms应用程序;默认字体问题是否已经解决了? - dpant
11个回答

50

这个被采纳的答案其实并没有回答问题,只是解释了为什么会出现这种行为。

其他一些答案提出了可靠的解决方法,但我发现最好的解决方案是创建一个基础表单,让应用程序中的所有表单都从这个基础表单继承,并在构造函数中将该基础表单的Font属性设置为SystemFonts.MessageBoxFont。这不仅确保应用程序在运行时根据用户环境选择正确的字体(避免Hans Passant可能引起的问题——如果XP没有安装Office 2007,则在缺少Segoe UI的情况下会使用Microsoft Sans Serif),而且还为当前Windows字体提供设计时支持。在设计时使用正确的字体解决了Josuegomes指出的问题,因为创建在表单上的任何容器控件都将使用表单在设计时使用的字体。

除了以上优点之外,这还使您无需记住修改每个表单的构造函数,并确保应用程序中的所有表单的一致性,同时还为您提供了放置其他常见功能的地方。我以几种不同的方式使用它,例如p/invoking等修复WinForms实现中的错误。

这种方法剩下的唯一问题是如果您想为特定控件设置字体样式,比如加粗。最好的地方仍然是在该表单的构造函数中,从该表单的字体作为基础开始修改样式:

myControl.Font = New Font(Me.Font, FontStyle.Bold)

36

在表单构造函数中的 InitializeComponent() 前面添加以下代码:

this.Font = SystemFonts.MessageBoxFont;

这似乎适用于Windows XP和Windows Vista。


15

看看这篇博客文章,它谈到了Forms中的默认字体问题,这导致了您遇到的问题,以及微软的Connect Bug回应。简而言之,似乎Forms无法获取(正确的)默认Windows字体(您可能已经更改了它)。


13

是的,它使用由GetStockObject(DEFAULT_GUI_FONT)返回的字体。这个字体是MS Sans Serif,是一种老式字体,在大多数计算机上已经消失了。字体映射器将其转换为Microsoft Sans Serif。

据我所知,没有记录的程序可以更改默认字体,SDK文档明确提到了MS Sans Serif。如果你想要Segoe字体,你必须请求它。但这样做并不安全,因为还有许多未安装Office 2007的XP计算机。在没有Segoe可用的机器上,字体映射器会将其转换为其他字体。我不确定会出现什么,因为我没有这样的计算机了。


"MS Sans Serif" 不同于 "Microsoft Sans Serif"。前者是一种旧的位图字体,而后者仍然广泛用于Win10(控制面板、文件属性、基本上所有内置应用程序的对话框类型窗口,例如regedit.exe或gpedit.msc中的[非主窗口]对话框)。DEFAULT_GUI_FONT 具体为 8pt 的 "MS Shell Dlg"。在 WinXP 到 Win10 上,“MS Shell Dlg” 是“Microsoft Sans Serif”,但并不普遍适用。例如,在中文或日文系统上,它是一种不同的字体。它之所以广泛使用,是因为本地对话框资源默认使用它,包括Windows自己的程序。 - dialer

6

.NET Core中,我们(.NET团队)将默认字体更新为Segoe UI,在.NET 6中,我们添加了一个API来更改应用程序中所有默认字体。

在项目文件中的<PropertyGroup>中添加:

<ApplicationDefaultFont>Curlz MT, 18pt</ApplicationDefaultFont>

这将更新在设计器和运行应用程序中使用默认字体的每个控件(即您没有显式覆盖的所有内容)。

您还可以像下面的示例一样直接在Main()中调用Application.SetDefaultFont()

static void Main()
{
    ApplicationConfiguration.Initialize();

    Application.SetDefaultFont(new Font(new FontFamily("Curlz MT"), 18f));

    Application.Run(new AirQualityForm());
}

这将更新您运行的应用程序中的字体,但不会影响设计师。


3

组框内的控件确实不受表单 Font 属性的影响。原因是容器控件中的控件被视为容器控件(如 groupbox)的子级,而不是主窗体的子级。为了使所有控件(包括组框中的控件)正确缩放,您可以使用类似下面的代码:

        foreach (Control ctr in this.Controls)
        {
            ctr.Font = SystemFonts.IconTitleFont;

            // controls in groupboxes are not child of main form
            if (ctr.HasChildren)
            {
                foreach (Control childControl in ctr.Controls)
                {
                    childControl.Font = SystemFonts.IconTitleFont;
                }
            }        
        }

1
< p > Control.DefaultFont 是只读的;一种hacky的方法是使用反射来覆盖它。

Type settingsType = typeof(Control);
var defaultFontField = settingsType.GetField("defaultFont", BindingFlags.Static | BindingFlags.NonPublic);
defaultFontField.SetValue(null, new Font("Segoe UI", 8.25F));

请确保有一名UT关注此代码,如果框架实现发生更改,则没有API合同可保护您。

还要注意表单设计器,它大多数时间会在.designer类中逐字插入字体。


在某些情况下,使用远程桌面连接可能无法正常工作。如果服务器和客户端具有不同的默认字体(例如,在英语Windows上为8.25 pt Microsoft Sans Serif,而在中文Windows上为9 pt SimSun),那么启动或结束RDP会话将导致许多控件(包括标签)开始使用真实的默认字体进行渲染。当发生这种情况时,Font属性将继续返回你覆盖的值。 - Billy

1
尝试这个,点击表单并更改字体大小,例如我将表单的字体大小更改为12pt,然后通过将文本框拖到表单上进行测试。您会发现,文本框的大小也已更改为12pt。我只是偶然得到了这个解决方案。

你有没有注意到一个问题在2008年被问了?回答得相当晚了。 - m.cekiera
2
是的,我明白了。但是在2015年,我仍然需要这个问题的答案,而我是偶然解决了这个问题,正如我所说的那样。因此,我认为我应该告诉其他可能遇到类似问题的人这个解决方案。 - P D

1
将表单的字体属性设置为SystemFonts.DialogFont无法正常工作,如果您有与控件相关联的分组框。分组框内的控件不受表单字体属性的影响。我通过为每个分组框设置字体属性为SystemFonts.DialogFont来“解决”了这个问题。

0

我尝试了一个针对net472/net48netcoreapp3.1的示例应用程序。在.NET应用程序中,Control.DefaultFont始终返回Microsoft Sans Serif而不是缩放。但是,在.NET Core 3.1应用程序中,Control.DefaultFont返回Win7/10上的系统字体,并且缩放得很好。因此,我认为他们最终在Core中解决了这个问题。


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