如何在 .NET WinForms 应用程序中控制字体 DPI [英] How to control the font DPI in .NET WinForms app

查看:27
本文介绍了如何在 .NET WinForms 应用程序中控制字体 DPI的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我为一家小型企业创建了一个应用.办公室的一些员工无法正确查看表格.原因是他们将 DPI 设置设置为 96dpi 以上.有没有人知道一种方法来控制这个?

I created an app for a small business. Some of the employees in the office can not see the form correctly. The reason is they have their DPI setting set to above 96dpi. Does anybody know of a way to control this?

对于所有使用过 winforms 应用程序的人来说,您如何控制表单布局以使 DPI 不影响应用程序的外观?

For all of you who have experience with winforms apps, how do you control your form layout so that DPI does not affect the look of the application?

推荐答案

假设您不尝试尊重用户的 UI 字体选择 (SystemFonts.IconTitleFont),并且仅将表单硬编码为一种字体大小(例如 Tahoma 8pt, Microsoft Sans Serif 8.25pt),您可以将表单的 AutoScaleMode 设置为 ScaleMode.Dpi.

Assuming you do not try to honor the user's UI font choice (SystemFonts.IconTitleFont), and hard-code your forms for one font size only (e.g. Tahoma 8pt, Microsoft Sans Serif 8.25pt), you can set your form's AutoScaleMode to ScaleMode.Dpi.

这将通过调用 Form.Scale() 按因子 CurrentDpiSetting/96 缩放表单和大多数子控件的大小>,它依次在自身和所有子控件上递归调用受保护的 ScaleControl() 方法.ScaleControl 将根据新缩放因子的需要增加控件的位置、大小、字体等.

This will scale the size of the form and most of it child controls by the factor CurrentDpiSetting / 96 by calling Form.Scale(), which in turns calls the protected ScaleControl() method recursivly on itself and all child controls. ScaleControl will increase a control's position, size, font, etc as needed for the new scaling factor.

警告:并非所有控件都能正确缩放.的列例如,listview 不会得到随着字体变大变宽.在为了处理你必须手动执行额外的缩放为必需的.我通过覆盖受保护的 ScaleControl() 方法,以及手动缩放列表视图列:

Warning: Not all controls properly scale themselves. The columns of a listview, for example, will not get wider as the font gets larger. In order to handle that you'll have to manually perform additional scaling as required. i do this by overriding the protected ScaleControl() method, and scaling the listview columns manually:

public class MyForm : Form
{
   protected override void ScaleControl(SizeF factor, BoundsSpecified specified)
   {
      base.ScaleControl(factor, specified);
      Toolkit.ScaleListViewColumns(listView1, factor);
   }
}

public class Toolkit  
{
   /// <summary>
   /// Scale the columns of a listview by the Width scale factor specified in factor
   /// </summary>
   /// <param name="listview"></param>
   /// <param name="factor"></param>
   /// <example>/*
   /// protected override void ScaleControl(SizeF factor, BoundsSpecified specified)
   /// {
   ///    base.ScaleControl(factor, specified);
   ///    
   ///    //ListView columns are not automatically scaled with the ListView, so we
   ///    //must do it manually
   ///    Toolkit.ScaleListViewColumns(lvPermissions, factor);
   /// }
   ///</example>
   public static void ScaleListViewColumns(ListView listview, SizeF factor)
   {
      foreach (ColumnHeader column in listview.Columns)
      {
          column.Width = (int)Math.Round(column.Width * factor.Width);
      }
   }
}

<小时>

如果您只是使用控件,这一切都很好.但是,如果您曾经使用过任何硬编码的像素大小,则需要按表单的当前比例因子来缩放像素宽度和长度.一些可能具有硬编码像素大小的情况示例:


This is all well and good if you're just using controls. But if you ever use any hard-coded pixel sizes, you'll need to scale your pixel widths and lengths by the current scale factor of the form. Some examples of situations that could have hard-coded pixel sizes:

  • 绘制一个 25 像素高的矩形
  • 在表单上的位置 (11,56) 绘制图像
  • 将图标拉伸至 48x48
  • 使用 Microsoft Sans Serif 8.25pt 绘制文本
  • 获取图标的 32x32 格式并将其填充到 PictureBox 中

如果是这种情况,您需要按当前缩放因子"缩放这些硬编码值.遗憾的是没有提供当前"的比例因子,需要我们自己记录.解决方案是假设初始比例因子为 1.0,每次调用 ScaleControl() 时,将运行比例因子修改为新因子.

If this is the case, you'll need to scale those hard-coded values by the "current scaling factor". Unfortunatly the "current" scale factor is not provided, we need to record it ourselves. The solution is to assume that initially the scaling factor is 1.0 and each time ScaleControl() is called, modify the running scale factor by the new factor.

public class MyForm : Form
{
   private SizeF currentScaleFactor = new SizeF(1f, 1f);

   protected override void ScaleControl(SizeF factor, BoundsSpecified specified)
   {
      base.ScaleControl(factor, specified);

      //Record the running scale factor used
      this.currentScaleFactor = new SizeF(
         this.currentScaleFactor.Width * factor.Width,
         this.currentScaleFactor.Height * factor.Height);

      Toolkit.ScaleListViewColumns(listView1, factor);
   }
}

最初的比例因子是 1.0.如果表单按 1.25 缩放,则缩放因子变为:

Initially the scaling factor is 1.0. If form is then scaled by 1.25, the scaling factor then becomes:

1.00 * 1.25 = 1.25    //scaling current factor by 125%

如果表单被缩放0.95,新的缩放因子变成

If the form is then scaled by 0.95, the new scaling factor becomes

1.25 * 0.95 = 1.1875  //scaling current factor by 95%

使用 SizeF(而不是单个浮点值)的原因是 x 和 y 方向的缩放量可能不同.如果表单设置为 ScaleMode.Font,则表单将缩放到新的字体大小.字体可以有不同的纵横比(例如 Segoe UI 是比 Tahoma 更高的字体).这意味着您必须独立缩放 x 和 y 值.

The reason a SizeF is used (rather than a single floating point value) is that scaling amounts can be different in the x and y directions. If a form is set to ScaleMode.Font, the form is scaled to the new font size. Fonts can have different aspect ratios (e.g. Segoe UI is taller font than Tahoma). This means you have to scale x and y values independantly.

因此,如果您想在 (11,56) 位置放置控件,则必须从以下位置更改定位代码:

So if you wanted to place a control at location (11,56), you would have to change your positioning code from:

Point pt = new Point(11, 56);
control1.Location = pt;

Point pt = new Point(
      (int)Math.Round(11.0*this.scaleFactor.Width),
      (int)Math.Round(56.0*this.scaleFactor.Height));
control1.Location = pt;

如果您要选择字体大小,同样适用:

The same applies if you were going to pick a font size:

Font f = new Font("Segoe UI", 8, GraphicsUnit.Point);

必须变成:

Font f = new Font("Segoe UI", 8.0*this.scaleFactor.Width, GraphicsUnit.Point);

并且将 32x32 图标提取到位图会从:

And extracting a 32x32 icon to a bitmap would change from:

Image i = new Icon(someIcon, new Size(32, 32)).ToBitmap();

Image i = new Icon(someIcon, new Size(
     (int)Math.Round(32.0*this.scaleFactor.Width), 
     (int)Math.Round(32.0*this.scaleFactor.Height))).ToBitmap();

支持非标准 DPI 显示是所有开发人员都必须承担的税应该支付.但事实上没有人愿意,这就是为什么 微软放弃并加入Vista 的图形卡扩展任何应用程序的能力,这些应用程序不能正确处理高 dpi.

Supporting non-standard DPI displays is a tax that all developers should pay. But the fact that nobody wants to is why Microsoft gave up and added to Vista the ability for the graphics card to stretch any applications that don't say they properly handle high-dpi.

这篇关于如何在 .NET WinForms 应用程序中控制字体 DPI的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆