高DPI监视器上相同的字体看起来不一样

时间:2016-10-25 22:37:21

标签: winforms dpi

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

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

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

All controls have the same font size.

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

Requested font size does not match visible font size.

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

enter image description here

在搜索互联网后,我尝试了几件事来解决这个问题,包括:

  • 在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 vs. .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();
    }
    

1 个答案:

答案 0 :(得分:0)

这很疯狂,但确实有效。

我在互联网上看到的关于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。这种方法运作得相当好。