为什么会发生这种情况?如何确保我的应用程序看起来像普通的Windows应用程序?
这个被采纳的答案其实并没有回答问题,只是解释了为什么会出现这种行为。
其他一些答案提出了可靠的解决方法,但我发现最好的解决方案是创建一个基础表单,让应用程序中的所有表单都从这个基础表单继承,并在构造函数中将该基础表单的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)
在表单构造函数中的 InitializeComponent() 前面添加以下代码:
this.Font = SystemFonts.MessageBoxFont;
这似乎适用于Windows XP和Windows Vista。
看看这篇博客文章,它谈到了Forms中的默认字体问题,这导致了您遇到的问题,以及微软的Connect Bug回应。简而言之,似乎Forms无法获取(正确的)默认Windows字体(您可能已经更改了它)。
是的,它使用由GetStockObject(DEFAULT_GUI_FONT)
返回的字体。这个字体是MS Sans Serif,是一种老式字体,在大多数计算机上已经消失了。字体映射器将其转换为Microsoft Sans Serif。
据我所知,没有记录的程序可以更改默认字体,SDK文档明确提到了MS Sans Serif。如果你想要Segoe字体,你必须请求它。但这样做并不安全,因为还有许多未安装Office 2007的XP计算机。在没有Segoe可用的机器上,字体映射器会将其转换为其他字体。我不确定会出现什么,因为我没有这样的计算机了。
.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());
}
这将更新您运行的应用程序中的字体,但不会影响设计师。
组框内的控件确实不受表单 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;
}
}
}
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类中逐字插入字体。
我尝试了一个针对net472/net48
和netcoreapp3.1
的示例应用程序。在.NET应用程序中,Control.DefaultFont
始终返回Microsoft Sans Serif而不是缩放。但是,在.NET Core 3.1应用程序中,Control.DefaultFont
返回Win7/10上的系统字体,并且缩放得很好。因此,我认为他们最终在Core中解决了这个问题。