无论系统的DPI如何,如何使表单中的控件显示相同的大小和位置?

时间:2017-06-17 01:11:30

标签: forms delphi controls scale dpi

根据我的经验,我注意到有三种类型的应用程序:

  1. 与Windows DPI设置相符并正确缩放的内容。

  2. 始终将所有内容保持在同一像素位置并且不进行任何缩放(这是我想要的)。

  3. 那些无法应对非标准DPI设置的设备,因此它们的控件遍布各处。此类程序有时会建议用户更改其DPI设置。

  4. 我已经知道Win32 API中有SetProcessDPIAwareness()SetProcessDPIAware()个函数,Scaled类中有PixelsPerInchTForm个属性。

    我已经尝试过这些东西,在网上搜索,但我还没有找到或开发出任何可靠的方法。

1 个答案:

答案 0 :(得分:1)

实现您的目标:

  1. 在您的应用程序清单中声明您的程序可识别DPI。这将确保系统不会将程序扩展为窗口组合机制的一部分。
  2. 将每个表单的Scaled属性设置为False。这可以确保表单及其控件不会扩展到主流DPI。
  3. 在您的应用程序清单中使用此设置:

    <asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
      <asmv3:windowsSettings
           xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
        <dpiAware>True/PM</dpiAware>
      </asmv3:windowsSettings>
    </asmv3:application>
    

    重要的是声明程序是每个监视器DPI意识到的。否则,如果您只声明系统DPI感知,那么您仍然可以通过窗口组合机制找到窗口缩放。

    最后,如果您正在使用西雅图或更高版本,它本身支持每个监视器DPI感知,您需要禁用它。它应该足以覆盖每个顶级窗口的WM_DPICHANGED消息的处理,并且不响应该消息:

    type
      TBaseForm = class(TForm) // all forms in your program must derive from this base class
      protected
        procedure WMDpiChanged(var Msg: TMessage); message WM_DPICHANGED;
      end;
    
    ....
    
    procedure TBaseForm.WMDpiChanged(var Msg: TMessage);
    begin
      // return 0 to indicate that we have processed the message
      Msg.Result := 0;
    end;