我为小型企业创建了一个应用程序.办公室的一些员工无法正确查看表格.原因是他们的DPI设置设置为96dpi以上.有人知道控制这个的方法吗?
对于有winforms应用程序经验的所有人,如何控制表单布局以使DPI不影响应用程序的外观?
假设您没有尝试兑现用户的UI字体选择(SystemFonts.IconTitleFont),并且只对一种字体大小的表单进行硬编码(例如Tahoma 8pt,Microsoft Sans Serif 8.25pt),您可以将表单设置AutoScaleMode
为ScaleMode.Dpi
.
这将通过调用按比例缩放表单的大小和大部分子控件,后者依次对自身和所有子控件进行recursivly 调用.将根据新缩放因子的需要增加控件的位置,大小,字体等.CurrentDpiSetting / 96
Form.Scale()
ScaleControl()
ScaleControl
警告:并非所有控件都能正确缩放.例如,列表视图的列不会随着字体变大而变宽.为了处理这个问题,您必须根据需要手动执行其他扩展.我这样做是通过覆盖受保护的
ScaleControl()
方法,并手动缩放listview列:public class MyForm : Form { protected override void ScaleControl(SizeF factor, BoundsSpecified specified) { base.ScaleControl(factor, specified); Toolkit.ScaleListViewColumns(listView1, factor); } } public class Toolkit { ////// Scale the columns of a listview by the Width scale factor specified in factor /// /// /// ////* /// 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); /// } /// public static void ScaleListViewColumns(ListView listview, SizeF factor) { foreach (ColumnHeader column in listview.Columns) { column.Width = (int)Math.Round(column.Width * factor.Width); } } }
如果您只是使用控件,这一切都很好.但是,如果您使用任何硬编码像素大小,则需要根据表单的当前比例因子缩放像素宽度和长度.可能具有硬编码像素大小的情况的一些示例:
绘制一个25像素高的矩形
在表单上的位置(11,56)绘制图像
拉伸图标到48x48
使用Microsoft Sans Serif 8.25pt绘制文本
获取图标的32x32格式并将其填充到PictureBox中
如果是这种情况,您需要通过" 当前比例因子 " 来缩放这些硬编码值.不幸的是,没有提供"当前"比例因子,我们需要自己记录.解决方案是假设最初缩放因子为1.0并且每次ScaleControl()
调用时,通过新因子修改运行比例因子.
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
,则缩放因子变为:
1.00 * 1.25 = 1.25 //scaling current factor by 125%
如果然后缩放表单0.95
,则新的缩放因子变为
1.25 * 0.95 = 1.1875 //scaling current factor by 95%
使用a的原因SizeF
(而不是单个浮点值)是缩放量在x和y方向上可以不同.如果将表单设置为ScaleMode.Font
,则表单将缩放为新的字体大小.字体可以具有不同的宽高比(例如, Segoe UI比Tahoma更高的字体).这意味着您必须独立缩放x和y值.
因此,如果您想将控件放在位置(11,56)
,则必须更改定位代码:
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;
如果您要选择字体大小,则同样适用:
Font f = new Font("Segoe UI", 8, GraphicsUnit.Point);
必须成为:
Font f = new Font("Segoe UI", 8.0*this.scaleFactor.Width, GraphicsUnit.Point);
并将32x32图标提取到位图将改为:
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的应用程序.
通过全局搜索/替换将AutoScaleMode设置为在任何地方继承(即所有UserControl),然后在主窗体上将AutoScaleMode设置为Dpi.
我还发现布局容器比这种情况下的锚更好.