Delphi High DPI在自己的缩放和Windows缩放之间切换 [英] Delphi High DPI switch between own scaling and Windows scaling

查看:921
本文介绍了Delphi High DPI在自己的缩放和Windows缩放之间切换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的一些客户希望能够手动缩放我的应用程序(当Windows dpi设置为96时),因此我必须实现缩放。不幸的是,这些客户不能将Windows DPI设置为其他值,而让Windows扩展我的应用程序,因为他们使用的一些非常重要的应用程序在<96 DPI的分辨率下根本表现不佳。

Some of my customers want to be able to scale my application manually (when Windows dpi is set to 96), so I had to implement scaling. Unfortunately these customers cannot go with setting Windows DPI to an other value and let WIndows scale my app because some very important applications they use do not behave well at all on resolutions <> 96 DPI.

即使在200%的情况下,我也设法使Delphi 10.1的应用程序比例相当好,但是系数越高,比例就越看起来不太好。许多第三方组件需要进行特殊处理以进行缩放,即使如此,缩放比例也无法100%准确。尽管按窗口缩放的应用程序在高分辨率上看起来有些模糊,但是所有比例都是100%准确的,恕我直言,该应用程序看起来更加专业。

I managed to make my Delphi 10.1 application scale quite well even on 200% but the higher the factor becomes the more some proportions become "not so nice looking". Many 3rd party components need special treatment for scaling and even then do not scale 100% accurate. Although applications scaled by windows look a little blurry on high resolutions, all proportions are 100% accurate and imho the app looks much more professional.

所以我问自己是否可以创建一个设置,该设置允许Windows默认进行缩放,并且仅在客户希望与当前Windows缩放比例不同的缩放比例时自行缩放。此设置托管在应用程序启动时读取的可执行文件的Windows清单中。有没有办法在运行时(应用程序的早期启动)进行更改?创建两个具有不同清单的可执行文件肯定不是很好的解决方案。

So I asked myself whether it is possible to create a setting that allows to tell Windows to do the scaling as a default and only scale on my own if the customer wants a scaling that is different from the current Windows scaling. This setting is hosted in the Windows manifest of the executable that is read on start of the application. Is there a way to change it at runtime (early startup of the application)? Creating two executables with different manifests is surely no good solution.

感谢您的帮助

推荐答案

感谢Sertac Akyuz,我找到了解决问题的方法。在包含缩放代码的单元的初始化部分中,我可以在DPI-Awareness和Non-DPI-Awareness之间进行切换。重要的是,不要在应用程序清单中有此设置,这可以通过提供这样的自定义清单来实现(使用控件修饰并使用当前用户的权限运行):

Thanks to Sertac Akyuz I found a solution to my problem. In the Initialization part of the unit containing the scaling code I can switch between DPI-Awareness and Non-DPI-Awareness. It is important not to have this setting in the application manifest, which can be achieved by supplying a custom manifest like this (use control decoration and run with rights of current user):

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
 <dependency>
   <dependentAssembly>
     <assemblyIdentity
       type="win32"
       name="Microsoft.Windows.Common-Controls"
       version="6.0.0.0"
       publicKeyToken="6595b64144ccf1df"
       language="*"
       processorArchitecture="*"/>
   </dependentAssembly>
 </dependency>
 <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
   <security>
     <requestedPrivileges>
       <requestedExecutionLevel
         level="asInvoker"
         uiAccess="false"/>
       </requestedPrivileges>
   </security>
 </trustInfo>
</assembly>

这是根据注册表项进行的实际代码切换:

This is the actual code switching depending on a registry key:

// Set DPI Awareness depending on a registry setting
with TRegIniFile.create('SOFTWARE\' + SRegName) do
begin
  setting := readInteger('SETTINGS', 'scale', 0);
  Free;
end;
handle := LoadLibrary('shcore.dll');
if handle <> 0 then
begin
  setProcessDPIAwareness := GetProcAddress(handle, 'SetProcessDpiAwareness');
  if Assigned(setProcessDPIAwareness) then
  begin
    if setting < 2 then
      // setting <2 means no scaling vs Windows
      setProcessDPIAwareness(0)
    else
      // setting 2: 120%, 3: 140% vs. Windows
      // The actual used scaling factor multiplies by windows DPI/96
      setProcessDPIAwareness(1);
  end;
  FreeLibrary(handle);
  // Get windows scaling as Screen.PixelsPerInch was read before swiching DPI awareness
  // Our scaling routines now work with WinDPI instead of Screen.PixelsPerInch
  WinDPI:= Screen.MonitorFromWindow(application.handle).PixelsPerInch;
end;

此代码段的最后一行检索当前监视器的当前DPI,如screen.pixelsperinch似乎是初始化之前,对于不支持dpi的应用程序始终返回96。我在以后的所有缩放计算中都使用了winDPI的值,并且效果很好。

The last line of this snippet retrieves the current DPI for the current monitor as screen.pixelsperinch seems to be initialized before and does always return 96 as for a non dpi aware application. I use the value of winDPI in all subsequent scaling calculations and it works perfect.

这篇关于Delphi High DPI在自己的缩放和Windows缩放之间切换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆