我在C#中有一个表单应用程序。当我更改监视器的DPI时,所有控件都会移动。我使用了代码this.AutoScaleMode = AutoScaleMode.Dpi
,但是并不能避免该问题。
有人有主意吗?
我在C#中有一个表单应用程序。当我更改监视器的DPI时,所有控件都会移动。我使用了代码this.AutoScaleMode = AutoScaleMode.Dpi
,但是并不能避免该问题。
有人有主意吗?
Answers:
编辑:从.NET 4.7开始,Windows窗体改进了对High DPI的支持。在docs.microsoft.com上了解有关此内容的更多信息,但它仅适用于Win 10 Creators Update和更高版本,因此根据用户群的不同,可能尚不可行。
困难,但并非不可能。最好的选择当然是转到WPF,但这可能不可行。
我花了很多时间解决这个问题。以下是一些规则/准则,可使其在没有FlowLayoutPanel或TableLayoutPanel的情况下正常工作:
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); // for design in 96 DPI
我保证,如果您遵循这些准则,即使您已将控件放置在具有特定锚点的位置并且不使用流程图,也可以。我们以这种方式构建了一个应用程序,该应用程序可以部署在数百台具有不同DPI设置的计算机上,并且不再有任何投诉。所有表单/容器/网格/按钮/文本字段等大小均按字体正确缩放。图像也可以工作,但是在高DPI时它们往往会有点像素化。
编辑:此链接具有很多好的信息,尤其是如果您选择使用AutoScaleMode.DPI:链接到相关的stackoverflow问题
注意:当dpi更改时,这不能解决控件的移动问题。这只会修复文本模糊!
如何在高dpi设置中修复模糊的Windows窗体:
现在,转到Program.cs(或Main方法所在的文件)并将其更改为:
namespace myApplication
{
static class Program
{
[STAThread]
static void Main()
{
// ***this line is added***
if (Environment.OSVersion.Version.Major >= 6)
SetProcessDPIAware();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
// ***also dllimport of that function***
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern bool SetProcessDPIAware();
}
}
保存并编译。现在,您的表格应该看起来又酥脆了。
来源:http : //crsouza.com/2015/04/13/how-to-fix-blurry-windows-forms-windows-in-high-dpi-settings/
我终于找到了解决屏幕方向和DPI处理问题的方法。
Microsoft已经提供了一份说明文件,但有一点缺陷,它将完全杀死DPI处理。只需遵循以下文档中“为每个方向创建单独的布局代码”下提供的解决方案即可:
http://msdn.microsoft.com/zh-cn/library/ms838174.aspx
然后重要的部分!在每个末尾的Landscape()和Portrait()方法的代码中,添加以下行:
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
因此,这两种方法的代码如下:
protected void Portrait()
{
this.SuspendLayout();
this.crawlTime.Location = new System.Drawing.Point(88, 216);
this.crawlTime.Size = new System.Drawing.Size(136, 16);
this.crawlTimeLabel.Location = new System.Drawing.Point(10, 216);
this.crawlTimeLabel.Size = new System.Drawing.Size(64, 16);
this.crawlStartTime.Location = new System.Drawing.Point(88, 200);
this.crawlStartTime.Size = new System.Drawing.Size(136, 16);
this.crawlStartedLabel.Location = new System.Drawing.Point(10, 200);
this.crawlStartedLabel.Size = new System.Drawing.Size(64, 16);
this.light1.Location = new System.Drawing.Point(208, 66);
this.light1.Size = new System.Drawing.Size(16, 16);
this.light0.Location = new System.Drawing.Point(192, 66);
this.light0.Size = new System.Drawing.Size(16, 16);
this.linkCount.Location = new System.Drawing.Point(88, 182);
this.linkCount.Size = new System.Drawing.Size(136, 16);
this.linkCountLabel.Location = new System.Drawing.Point(10, 182);
this.linkCountLabel.Size = new System.Drawing.Size(64, 16);
this.currentPageBox.Location = new System.Drawing.Point(10, 84);
this.currentPageBox.Size = new System.Drawing.Size(214, 90);
this.currentPageLabel.Location = new System.Drawing.Point(10, 68);
this.currentPageLabel.Size = new System.Drawing.Size(100, 16);
this.addressLabel.Location = new System.Drawing.Point(10, 4);
this.addressLabel.Size = new System.Drawing.Size(214, 16);
this.noProxyCheck.Location = new System.Drawing.Point(10, 48);
this.noProxyCheck.Size = new System.Drawing.Size(214, 20);
this.startButton.Location = new System.Drawing.Point(8, 240);
this.startButton.Size = new System.Drawing.Size(216, 20);
this.addressBox.Location = new System.Drawing.Point(10, 24);
this.addressBox.Size = new System.Drawing.Size(214, 22);
//note! USING JUST AUTOSCALEMODE WILL NOT SOLVE ISSUE. MUST USE BOTH!
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); //IMPORTANT
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; //IMPORTANT
this.ResumeLayout(false);
}
protected void Landscape()
{
this.SuspendLayout();
this.crawlTime.Location = new System.Drawing.Point(216, 136);
this.crawlTime.Size = new System.Drawing.Size(96, 16);
this.crawlTimeLabel.Location = new System.Drawing.Point(160, 136);
this.crawlTimeLabel.Size = new System.Drawing.Size(48, 16);
this.crawlStartTime.Location = new System.Drawing.Point(64, 120);
this.crawlStartTime.Size = new System.Drawing.Size(248, 16);
this.crawlStartedLabel.Location = new System.Drawing.Point(8, 120);
this.crawlStartedLabel.Size = new System.Drawing.Size(48, 16);
this.light1.Location = new System.Drawing.Point(296, 48);
this.light1.Size = new System.Drawing.Size(16, 16);
this.light0.Location = new System.Drawing.Point(280, 48);
this.light0.Size = new System.Drawing.Size(16, 16);
this.linkCount.Location = new System.Drawing.Point(80, 136);
this.linkCount.Size = new System.Drawing.Size(72, 16);
this.linkCountLabel.Location = new System.Drawing.Point(8, 136);
this.linkCountLabel.Size = new System.Drawing.Size(64, 16);
this.currentPageBox.Location = new System.Drawing.Point(10, 64);
this.currentPageBox.Size = new System.Drawing.Size(302, 48);
this.currentPageLabel.Location = new System.Drawing.Point(10, 48);
this.currentPageLabel.Size = new System.Drawing.Size(100, 16);
this.addressLabel.Location = new System.Drawing.Point(10, 4);
this.addressLabel.Size = new System.Drawing.Size(50, 16);
this.noProxyCheck.Location = new System.Drawing.Point(168, 16);
this.noProxyCheck.Size = new System.Drawing.Size(152, 24);
this.startButton.Location = new System.Drawing.Point(8, 160);
this.startButton.Size = new System.Drawing.Size(304, 20);
this.addressBox.Location = new System.Drawing.Point(10, 20);
this.addressBox.Size = new System.Drawing.Size(150, 22);
//note! USING JUST AUTOSCALEMODE WILL NOT SOLVE ISSUE. MUST USE BOTH!
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); //IMPORTANT
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; //IMPORTANT
this.ResumeLayout(false);
}
对我来说就像魅力。
Creating Separate Layout Code for Each Orientation
部分与原始问题无关,一个winform应用程序。
看来这是Windows的问题。取出这两行可以修复所有问题。
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
这是我得到解决方案的地方:
根据经验:
AutoScaleMode
属性设置为None
ScaleByDPI函数将接收一个通常为表单的Control参数,然后递归地迭代所有子控件(如果(control.HasChildren == true)),并按应用程序控件的大小和字体的大小缩放位置和大小。操作系统配置的DPI。您也可以尝试对图像,图标和图形实施它。
ScaleByDPI函数的特别说明:
一种。对于所有具有默认字体大小的控件,您需要将其Font.Size设置为8.25。
b。您可以通过(control.CreateGraphics()。DpiX / 96)和(control.CreateGraphics()。DpiY / 96)获得devicePixelRatioX和devicePixelRatioY值。
C。您将需要通过基于control.Dock和control.Anchor值的算法来缩放Control.Size和Control.Location。请注意,control.Dock可能具有6个可能值之一,而control.Anchor可能具有16个可能值之一。
d。此算法将需要为下一个布尔变量设置值isDoSizeWidth,isDoSizeHeight,isDoLocationX,isDoLocationY,isDoRefactorSizeWidth,isDoRefactorSizeHeight,isDoRefactorLocationX,isDoRefactorLocationY,isDoClacLocationXBasedOnRight,isDoClacLocationYBasedOnBottom。
e。如果您的项目使用Microsoft控件以外的控件库,则此控件可能需要特殊处理。
以上(d。)bool变量的更多信息:
*有时需要一组控件(可能是一个按钮)在同一垂直线上一个接一个地放置,其“锚点”值包括“右”而不是“左”,或者它们需要在一个水平线上一个接一个地放置,锚点值包括“底部”而不是“顶部”,在这种情况下,您需要重新计算控件的“位置”值。
*如果控件的“锚点”包含“顶部和底部”和/或“左侧”和“右侧”,则需要重新分解控件的“大小和位置”值。
ScaleByDPI函数的用途:
一种。在任何Form构造函数的末尾添加下一个命令:ScaleByDPI(this);
b。同样,在将任何控件动态添加到Form时,对ScaleByDPI([ControlName])的调用也是如此。
在构造函数结束后动态设置任何控件的“大小”或“位置”时,创建并使用下一个函数之一即可获取“大小”或“位置”的缩放值:ScaleByDPI_X \ ScaleByDPI_Y \ ScaleByDPI_Size \ ScaleByDPI_Point
为了将您的应用程序标记为可识别DPI,请将dpiAware元素添加到应用程序的程序集清单中。
将所有Control.Font的GraphicsUnit设置为System.Drawing.GraphicsUnit.Point
在所有容器的* .Designer.cs文件中,将AutoScaleMode值设置为System.Windows.Forms.AutoScaleMode.None
在ComboBox和TextBox等控件中,更改Control.Size.Hieght无效。在这种情况下,更改Control.Font.Size将固定控件的高度。
如果表单的StartPosition值为FormStartPosition.CenterScreen,则需要重新计算窗口的位置。
由于Winform应用程序表单可能包含内容控件和图像,因此允许系统调整窗口大小不是解决方案,但是,如果您能够按DPI分辨率管理一个表单,并具有正确缩放的图像……那不是一个好主意,因为随着屏幕尺寸的增加,字体大小会减小。
当使用不同的DPI分辨率时,系统会强制您的表单重新定义其控件的大小,位置和字体(但不是图像),解决方案是在加载时在运行时更改表单的DPI,以使一切恢复到原始大小和位置。
这是可能的解决方案,我已经在纸牌游戏应用程序中进行了测试,该应用程序中有80个图像按钮,TabControls等。
在每个表单form_Load事件中,添加以下代码段:
Dim dpi As Graphics = Me.CreateGraphics
Select Case dpi.DpiX
Case 120
'-- Do nothing if your app has been desigbned with 120 dpi
Case Else
'-- I use 125 AND NOT 120 because 120 is 25% more than 96
Me.Font = New Font(Me.Font.FontFamily, Me.Font.Size * 125 / dpi.DpiX)
End Select
此外,还有一种无需重新启动即可在同一台计算机上测试各种分辨率的快速技巧:
在控制面板上,更改分辨率。不要重启!相反,请关闭您的会话并使用相同的用户打开一个新会话。
还有一个警告:如果在运行时设置控件的大小和位置,则应将相同的DPI因子(例如125 / Dpi.Dpix)应用于新坐标。因此,最好从application.startup事件中设置DPIFactor全局变量。
最后但并非最不重要的:
请勿以不同于原始分辨率的其他分辨率在Visual Studio中打开您的应用程序,否则当您打开每个表单时,“所有控件”都会移动并调整其大小,并且无法退回...
希望对您有所帮助,编程愉快。