【问题标题】:Identical fonts don't look identical on high DPI monitors相同的字体在高 DPI 显示器上看起来不一样
【发布时间】:2017-03-08 03:30:24
【问题描述】:

我有一个在旧系统上运行良好的 WinForms 应用程序,但我无法让它在 4k 显示器上看起来很好。有多个问题,关于这个主题的文章很多,但这个问题集中在一个特定的问题上。我可以设置不同的控件来使用相同的字体,但是在高 DPI 系统上,控件看起来会有很大不同。我该如何解决这个问题?

显然,我可以更改字体大小、移动控件等。但 Windows 在我的字体大小中添加了一个神秘因素。在不知道 Windows 在做什么的情况下,我很难撤消它!

在旧系统上,我的测试窗口看起来很完美:

在高 DPI 系统上,某些控件的字体大小与其他控件不同:

我尝试了几件事,包括在某些控件上手动设置字体,而不是从表单继承。如您所见,更改字体并不能解决问题:

在互联网上搜索后,我尝试了几种方法来解决此问题,包括:

  • 在 PROCESS_DPI_UNAWARE、PROCESS_SYSTEM_DPI_AWARE 和 PROCESS_PER_MONITOR_DPI_AWARE 之间更改应用程序
  • 明确changing the font,而不是使用表单的字体。
  • 在旧系统上构建与在高 DPI 系统上构建。
  • 在设置为 96 DPI / 100% 的显示器上构建与在同一台计算机上设置为 192 DPI / 200% 的显示器上构建。
  • 在 Visual Studio 的设计器中构建表单与在纯 C# 代码中构建表单。
  • .Net 4.0 与 .Net 4.6.1
  • Visual Studio 2010 与 Visual Studio 2015

我只发现一件事解决了我的问题。不幸的是,我必须在目标机器上做,而不是在我正在构建它的机器上。所以这不是一个实际的解决方案。有关详细信息,请参阅“重复步骤”下的第二项。

重复步骤:

  • 很多表单上的很多控件都会发生这种情况。请参阅下面的代码示例以获取一个简单的小演示。这就是我得到上面截图的方式。
  • 我可以通过一个系统设置使这个问题出现或消失。如果您将主显示器更改为 96 DPI / 100% 缩放,然后重新启动,您将获得所有字体都符合要求的良好结果。如果您将主显示器更改为不同的 DPI 设置,然后重新启动,您会看到不好的结果。

    private void newFormButton_Click(object sender, EventArgs e)
    {
        Font copyOfFont = new Font(Font, FontStyle.Strikeout);
        Form form = new Form();
        form.Font = Font;
        string sample = "Abc 123 :)";
        int padding = 6;
        Label label = new Label();
        label.Text = sample;
        label.Top = padding;
        label.Left = padding;
        label.Font = copyOfFont;
        label.Parent = form;
        Button button = new Button();
        button.Text = sample;
        button.Top = label.Bottom + padding;
        button.Left = padding;
        button.Width = label.Width + padding * 2;
        button.Height = label.Height + padding * 2;
        button.Parent = form;
        TextBox textBox = new TextBox();
        textBox.Text = sample;
        textBox.Size = button.Size;
        textBox.Top = button.Bottom + padding;
        textBox.Left = padding;
        textBox.Parent = form;
        ListBox listBox = new ListBox();
        listBox.Items.Add(sample);
        listBox.Items.Add(sample);
        listBox.Width = button.Width;
        listBox.Height = button.Height * 2;
        listBox.Top = textBox.Bottom + padding;
        listBox.Left = padding;
        listBox.Font = copyOfFont;
        listBox.Parent = form;
        form.Show();
    }
    

【问题讨论】:

  • 您是指文本框中的字体大小与 HiDPI 示例中的标签不同吗?
  • 是的,文本框和列表框的字体大小相同,按钮和标签的字体大小不同。它们都应该具有相同的大小。

标签: winforms dpi


【解决方案1】:

这很疯狂,但它确实有效。

我在互联网上看到的关于 DPI 虚拟化的所有内容都表明 Windows 默认会自动将进程设置为 PROCESS_DPI_UNAWARE。因此,除非您明确选择其他两个设置之一,否则您的应用程序在高分辨率显示器上应该看起来不错。它可能有点模糊,但看起来应该没有我上面展示的例子那么糟糕。

显然不是正确的。默认值取决于计算机,并且取决于日期。我的解决方案:明确将应用程序设置为使用 PROCESS_DPI_UNAWARE。我在下面包含了一个代码示例。

请注意,您应该能够使用清单来处理这个问题。一些消息来源说这是首选方式,而不是使用 C# 代码。我们的结果好坏参半。 C# 代码选项似乎更可靠。

    [DllImport("shcore.dll")]
    static extern int SetProcessDpiAwareness(_Process_DPI_Awareness value);

    enum _Process_DPI_Awareness
    {
        Process_DPI_Unaware = 0,
        Process_System_DPI_Aware = 1,
        Process_Per_Monitor_DPI_Aware = 2
    }


    public MainForm()
    {

        //int result = SetProcessDpiAwareness(_Process_DPI_Awareness.Process_System_DPI_Aware);
        //int result = SetProcessDpiAwareness(_Process_DPI_Awareness.Process_Per_Monitor_DPI_Aware);
        int result = SetProcessDpiAwareness(_Process_DPI_Awareness.Process_DPI_Unaware);
        System.Diagnostics.Debug.Assert(result == 0);

这适用于许多不同的开发人员机器。我们即将开始将修复程序发送给 Beta 测试人员。

总结

  1. O/S 为在高 DPI 系统上运行的旧程序提供了一种兼容模式。
  2. WinForms 和 O/S 提供了用于根据系统的 DPI 手动更改控件大小的工具 或当前监视器。
  3. #1 和#2 都有严重的错误!
  4. 从一台计算机到另一台计算机的细节差异很大。
  5. 修复 #2 会更 强大的选择,但据我所知,这是不可能的 解决这个问题。
  6. 相反,我修复了 #1。效果相当不错。

【讨论】:

    猜你喜欢
    • 2020-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-07
    • 2015-12-07
    • 2020-06-15
    相关资源
    最近更新 更多