我有一个问题,一个应用程序(用Delphi编写)在所有系统上都以默认的96 DPI设置正常运行,但在不同的系统上,在"150%文本大小“(内部144 dpi)设置下运行不一致。似乎在某些系统上,我的应用程序的某些文本/字体部分正在被拉伸,而在其他系统上,它们却没有。我会认为我的应用程序,在某个版本的Windows (Win7)上,在某个DPI上,应该有同样的表现。
要么我的应用程序让Windows知道它不需要DPI虚拟化功能,要么它不需要。这就是我所理解的。我不明白的是,DPI的变化如何会导致两台机器的外观不同,这两台机器都运行Windows7,都是144 dpi,以相同的固定大小显示相同的字体和表单。
DPI虚拟化中是否有一些与配置相关的元素需要在windows (注册表等)中进行检查?否则,如何排除故障并知道客户端窗口中是否正在执行DPI虚拟化?
在Delphi中,如果不想缩放,就必须将TForm.Scaled属性设置为false。但我不明白的是,当主窗体的缩放属性为true时,我不能总是预测结果。
在我的应用程序中最让我困惑的是,我有一个只在我的大型真实应用程序中行为不正常的控件,但它在我试图调试该控件的独立应用程序中不会行为异常。为了了解独立应用程序中的控制行为,我被迫制作了一个演示应用程序,其中我通过清单文件强制DPI感知。然后,我可以重现控件绘制毛刺,尽管是以不同的形式。
这是我在我的演示应用程序中使用的清单文件,它暴露了我的控件在处理windows中的高dpi设置时遇到的问题。然而,我发现一件奇怪的事情是,应用程序有可能
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<asmv3:windowsSettings
xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware>true</dpiAware>
</asmv3:windowsSettings>
</asmv3:application>
<assemblyIdentity version="14.0.3615.26342" processorArchitecture="*"
name="TestProject" type="win32"></assemblyIdentity>
<description>High DPI Controls Test App</description>
</assembly>
这里有一个例子,当我在我的应用程序中禁用DPI虚拟化时,我的应用程序中的控件被搞乱的大约30个地方之一。通过关闭我表单中的Scaled属性,解决了这个特殊的问题。但在其他地方,使用TForm.Scaled=false会导致问题,而在某些情况下,它会修复问题:
更新:事实证明,我的一些控件使用GDI+,并且GDI+上下文中的字体行为与普通GDI+上下文中的字体行为不同,至少对于某些使用GDI+的第三方控件是不同的。这是令人头疼的主要原因。其次,在VCL中,对于DPI感知,有不稳定的测试覆盖率和定义不明确的需求。一些VCL控件基于MS Common控件,虽然可以公平地说,底层通用控件可能在高DPI的情况下工作得很好,但并不是所有的VCL控件包装器都能正常工作。因此,检查应用程序在其所有控件中的高DPI感知,以及在所有可用windows 7主题中的正确行为:
..and清单还在继续,作为一个应用程序开发人员,你有一个相当沉重的负担。无论你是delphi用户并使用VCL,还是MFC/ATL C++开发人员,在我看来,支持所有各种古怪的窗口模式几乎是一个沉重的负担。所以大多数人都不会费心去做。我说的对吗?
发布于 2011-02-25 01:30:26
事实证明,当系统DPI从默认的96 dpi值更改时,我的应用程序中的怪癖有三个主要阵营:
总而言之,与过去相比,这些变化现在并没有太大的不同(复杂),当时Windows XP和其他版本的Windows为您提供了“字体大小”的选择,而现在,Windows 7 UI体验试图相当深入地隐藏字体大小选项,并为您提供了一个“文本大小”更改用户界面,该界面修改了表面之下的系统DPI。这两种改变用户体验的方法都会导致几乎每个用户在至少一个主要的商业应用程序上出现问题,而这些应用程序看起来不是很好,或者不能正确处理由此产生的更改。随着超高点间距显示器在消费PC领域变得越来越普遍,这个问题可能会变得越来越严重,需要围绕更合适的框架进行UI设计。
发布于 2011-02-22 23:57:27
你需要用下面这样的部分来表明你的应用程序是DPI感知的:
<asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware>true</dpiAware>
</asmv3:windowsSettings>
</asmv3:application>
如果你这样做,你将不会得到DPI虚拟化。
您并不打算使用DPI虚拟化,所以我认为尝试弄清楚它是如何工作的没有什么意义。它很容易依赖于显卡驱动程序。我们几乎不可能解释为什么虚拟化是这样的:你甚至没有给出任何屏幕截图,硬件细节等。然而,你根本不应该费心去诊断这个问题。显示为dpiaware,这不是问题。
作为参考,我提供给你:
发布于 2011-06-24 08:44:47
实际上,这是一个不同的问题。
您的表单不应该随着用户的字体大小而变大,它们应该随着字体大小的而变大。
Delphi's default form font是8pt Tahoma。
8pt Tahoma字符是:6.08px * 13px
。
从Windows Vista开始,默认字体为9pt Segoe UI。
9pt Segoe UI字符为:6.81px * 15px
。
你的Windows应用程序应该遵循用户的字体偏好(如IconTitleFont
)。
我的Windows字体首选是12pt Segoe UI,它的平均字符大小为:8.98px * 21px
这意味着,如果您使用Tahoma 8pt (13px高)设计窗体,则需要将窗体和所有子控件缩放162%:
scaleFactor = (userFontSize / designedFontSize)
= 21px / 13px
= 1.615
如果你很小心,你会注意到改变DPI仅仅是改变字体大小的一种特殊情况。您的 8pt 字体仍为8pt,但8PT可转换为更多像素。如果您运行131dpi ( Windows 7中的136%缩放设置),则:
9pt Segoe UI, 96dpi = 6.81px x 15px
9pt Segoe UI, 131dpi = 8.98px x 21px
注:我选择
131dpi
和12pt
作为示例并不是巧合。在工作中,我运行96dpi,但12pt。在家里,我运行9pt但131dpi。两者都有相同的像素字体高度,21px。
最后,您需要根据大小差异调用ScaleControl
:
procedure StandardizeFormFont(Form: TForm);
var
iconTitleFontName: string;
iconTitleFontSizePixels: Integer;
currentFontSizePixels: Integer;
begin
GetIconTitleFont(iconTitleFontName, iconTitleFontSizePixels);
//Change font face first
//Some fonts are inheriently taller than others
//(even at the same point size)
Form.Font.Name := iconTitleFontName;
//Get the form's current font height (in pixels)
currentFontSizePixels := Form.Font.Height; //negative number, but so is iconTitleFontSizePixels
Form.ScaleBy(iconTitleFontSizePixels, currentFontSizePixels);
end;
实际上,这段代码非常简单。许多子控件需要手动更新:
实际上,我们使用的是一个超级花哨的StandardizeFormFont
版本,它递归地遍历窗体上的所有控件,并且最好根据控件的内容来调整每个控件。
Delphi的每个控件都应该覆盖它的ScaleControl
方法,并做出它需要的调整:
protected
procedure ChangeScale(M, D: Integer); override;
https://stackoverflow.com/questions/5080380
复制相似问题