我在C#中有一个表单应用程序。当我更改显示器的DPI时,所有控件都会移动。
我使用了代码this.AutoScaleMode = AutoScaleMode.Dpi
,但它没有避免这个问题。
有没有人有想法?
答案 0 :(得分:102)
编辑:从.NET 4.7开始,Windows窗体改进了对高DPI的支持。 Read more about it on 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:link to related stackoverflow question
答案 1 :(得分:14)
我终于找到了屏幕方向和DPI处理问题的解决方案 微软已经提供了一个解释它的文档,但有一点点可以完全破坏DPI处理。 只需按照下面的文档“为每个方向创建单独的布局代码”中提供的解决方案 http://msdn.microsoft.com/en-us/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);
}
对我来说就像魅力一样。
答案 2 :(得分:5)
如何在高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/
答案 3 :(得分:4)
看起来这是Windows的一个问题。取出这两条线修好了一切。
ng build --base-href=/path/to/your/application/dist/
这是我得到解决方案的地方:
答案 4 :(得分:3)
在Windows窗体中设计DPI感知应用程序真的很难。您必须使用在更改DPI时正确调整大小的布局容器(例如TableLayoutPanel或FlowLayoutPanel)。所有控件也需要调整大小。这些容器的配置可能是一个挑战。
对于简单的应用程序,它可以在合理的时间内完成,但对于大型应用程序,它确实很多工作。
答案 5 :(得分:2)
根据经验:
AutoScaleMode
属性设置为None
答案 6 :(得分:1)
ScaleByDPI函数将接收一个通常是表单的Control参数,然后递归遍历所有子控件(if(control.HasChildren == true)),并缩放应用程序控件的大小和位置。 OS配置DPI的字体大小和大小。您也可以尝试将其用于图像,图标和图像。图形。
ScaleByDPI功能的特别说明:
一个。对于具有默认字体大小的所有控件,您需要将其Font.Size设置为8.25。
湾您可以通过(control.CreateGraphics()。DpiX / 96)和(control.CreateGraphics()。DpiY / 96)获取devicePixelRatioX和devicePixelRatioY值。
℃。你需要规模Control.Size& Control.Location基于控制的算法.Dock& control.Anchor值。请注意,control.Dock可能有6个可能值中的1个和该控件.Anchor可能有16个可能值中的1个。
d。此算法需要设置值为下一个bool变量isDoSizeWidth,isDoSizeHeight,isDoLocationX,isDoLocationY,isDoRefactorSizeWidth,isDoRefactorSizeHeight,isDoRefactorLocationX,isDoRefactorLocationY,isDoClacLocationXBasedOnRight,isDoClacLocationYBasedOnBottom。
即如果您的项目使用Microsoft控制之外的控件库,则此控件可能需要特殊处理。
以上(d。)bool变量的更多信息:
*有时一组控件(可能是按钮)需要在同一垂直线上一个接一个地放置,并且它们的Anchor值包括Right但不是Left,或者它们需要在同一水平线上一个接一个地放置,它们的Anchor值包括Bottom但不包括Top,在这种情况下,您需要重新计算控件位置值。
*如果控件中Anchor包含Top&底部和\或左边&是的,你需要重新控制尺寸和尺寸。位置值。
ScaleByDPI功能的使用:
一个。将下一个命令添加到任何Form构造函数的结尾:ScaleByDPI(this);
湾此外,当向FormB调用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,则需要重新计算窗口的位置。
答案 7 :(得分:1)
我为此苦苦挣扎了一段时间,最终我为 Windows 10 和其他可能的系统找到了一个超级简单的解决方案。
在您的 WinForms App.config
文件中粘贴:
<System.Windows.Forms.ApplicationConfigurationSection>
<add key="DpiAwareness" value="PerMonitorV2" />
</System.Windows.Forms.ApplicationConfigurationSection>
然后创建一个 app.manifest
文件并在此行中粘贴或注释:
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
完成上述操作后,我能够在 4k 屏幕上获得出色的 DPI 结果。
答案 8 :(得分:-1)
由于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中使用除原始分辨率之外的其他分辨率打开您的应用程序,否则当您打开每个表单时,所有控件都会移动并调整大小,并且无法返回......
希望这有帮助,快乐编程。