首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >在Windows Vista和Windows 7中排除DPI虚拟化和支持DPI的应用程序故障

在Windows Vista和Windows 7中排除DPI虚拟化和支持DPI的应用程序故障
EN

Stack Overflow用户
提问于 2011-02-22 23:48:26
回答 4查看 11.3K关注 0票数 18

我有一个问题,一个应用程序(用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设置时遇到的问题。然而,我发现一件奇怪的事情是,应用程序有可能

代码语言:javascript
复制
<?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主题中的正确行为:

  1. 航空玻璃打开,96dpi (大多数现代hardware)
  2. basic主题上的默认外观(航空玻璃关闭)但xp themes enabled
  3. classic Win7 win2000关闭玻璃的地方,以及xp级别主题,
  4. 高对比度白色
  5. 高对比度设置-96 DPI以外的

..and清单还在继续,作为一个应用程序开发人员,你有一个相当沉重的负担。无论你是delphi用户并使用VCL,还是MFC/ATL C++开发人员,在我看来,支持所有各种古怪的窗口模式几乎是一个沉重的负担。所以大多数人都不会费心去做。我说的对吗?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2011-02-25 01:30:26

事实证明,当系统DPI从默认的96 dpi值更改时,我的应用程序中的怪癖有三个主要阵营:

  1. 应用程序的一些控件使用GDI,一些控件使用GDI+。至少在我使用的控件中,GDI和GDI+字体在不同的DPI上有一些不同。
  2. 我在delphi语言中使用了一个叫做VCL的框架。在这个Delphi VCL框架中,一些表单具有TForm.Scaled=true,而另一些表单具有TForm.Scaled=false。因为它要求您考虑缩放窗体中的每个控件,所以作为UI设计者,您会发现缩放窗体中的“丑陋”或不可接受的事情是很常见的。关闭缩放后,只剩下一些表单,这些表单要么被Windows 7本身在高DPI设置(DPI虚拟化模式)下拉大,要么看起来很小,因此,如果您愿意,可以忽略用户的“请求”,以获得您的96 dpi UI的144 dpi版本。其他人可能正在使用其他语言的其他框架,或者甚至可能使用非常老式的东西,比如Visual C++的对话框编辑器,在那里您可以使用“对话框单元”来设计对话框,这是另一种尝试将常规对话框布局从1:1对应到像素中分离出来的方法。缩放、拉伸和布局控件是UI设计的一个通用部分,必须以符合平台要求的方式来解决。在我的例子中,VCL做了很好的工作,让我设计了一个支持96dpi玻璃的航空应用程序,在其他DPI评级下也很好用,但我的大多数自定义控件都做不到。所以这是另一个坚持使用VCL自带的控件的原因:如果你关心高DPI支持,当你试图让高DPI支持工作时,你的工作就会变得更加困难。反过来,
  3. DPI虚拟化是由一个清单设置控制的,你必须明确地将其包含在你的应用程序中。由于我的应用程序已经有了一个自定义清单(不是当你点击项目设置中的Enable-windows-themes复选框时包含在你的Delphi应用程序中的那个清单),我能够一次又一次地打开和关闭这个DPI虚拟化,并在两种情况下测试我的应用程序。我发现我的应用程序在没有DPI虚拟化的情况下还不能运行,因此我让Windows保持其默认行为。如果其他人的应用程序使用100%的vcl控件,使用窗体缩放或一些其他技术来适当地调整自身的大小(例如来自DevExpress的VCL ExpressLayout控件),以各种字体大小和DPI间距,则可以很容易地在禁用DPI虚拟化的情况下工作。在我看来,最终,VCL的功能已经足够了,但对于真正的工业级解决方案,需要一个比VCL更高级的框架,以便正确地综合处理“高DPI环境”等问题,并且在这些情况下,第三方控制通常不能像当前的VCL那样工作。这样的框架问题在WPF框架(微软)和Java (wing)中非常明显,但不是VCL的经典"Win16/Win32公共控制框架“的一部分。

总而言之,与过去相比,这些变化现在并没有太大的不同(复杂),当时Windows XP和其他版本的Windows为您提供了“字体大小”的选择,而现在,Windows 7 UI体验试图相当深入地隐藏字体大小选项,并为您提供了一个“文本大小”更改用户界面,该界面修改了表面之下的系统DPI。这两种改变用户体验的方法都会导致几乎每个用户在至少一个主要的商业应用程序上出现问题,而这些应用程序看起来不是很好,或者不能正确处理由此产生的更改。随着超高点间距显示器在消费PC领域变得越来越普遍,这个问题可能会变得越来越严重,需要围绕更合适的框架进行UI设计。

票数 6
EN

Stack Overflow用户

发布于 2011-02-22 23:57:27

你需要用下面这样的部分来表明你的应用程序是DPI感知的:

代码语言:javascript
复制
<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,这不是问题。

作为参考,我提供给你:

票数 11
EN

Stack Overflow用户

发布于 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%:

代码语言:javascript
复制
scaleFactor = (userFontSize / designedFontSize)
            = 21px / 13px
            = 1.615

如果你很小心,你会注意到改变DPI仅仅是改变字体大小的一种特殊情况。您的 8pt 字体仍为8pt,但8PT可转换为更多像素。如果您运行131dpi ( Windows 7中的136%缩放设置),则:

代码语言:javascript
复制
9pt Segoe UI,  96dpi = 6.81px x 15px
9pt Segoe UI, 131dpi = 8.98px x 21px

注:我选择131dpi12pt作为示例并不是巧合。在工作中,我运行96dpi,但12pt。在家里,我运行9pt但131dpi。两者都有相同的像素字体高度,21px。

最后,您需要根据大小差异调用ScaleControl

代码语言:javascript
复制
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;

实际上,这段代码非常简单。许多子控件需要手动更新:

  • listview列需要使用size
  • toolbar's获取wider
  • controls需要拥有其字体的adjusted
  • TImage控件需要将其图像拉伸到新的size
  • toolbar‘s需要使用较大的图像

实际上,我们使用的是一个超级花哨的StandardizeFormFont版本,它递归地遍历窗体上的所有控件,并且最好根据控件的内容来调整每个控件。

Delphi的每个控件都应该覆盖它的ScaleControl方法,并做出它需要的调整:

代码语言:javascript
复制
protected
   procedure ChangeScale(M, D: Integer); override;
票数 9
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5080380

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档