设置高 DPI 时防止我的 Win32 应用程序的 UI 元素按比例放大

Posted

技术标签:

【中文标题】设置高 DPI 时防止我的 Win32 应用程序的 UI 元素按比例放大【英文标题】:Prevent my Win32 application's UI elements from being scaled up when high DPI is set 【发布时间】:2013-04-10 08:02:04 【问题描述】:

当窗口设置为“将文本大小调整为“125%”时,我的 Win32 应用程序的 UI(但不是它的窗口大小)会按比例放大。这会导致文本字符串被截断并且 UI 元素从边缘消失窗户。

我想防止这种情况发生,这样文本就不会被放大,并且应用程序可以正确显示。由于让这个旧的旧版应用程序正确识别 DPI 的时间投入太高,我只想通过调整 UI 元素的大小来防止 Windows 破坏 UI 来使该应用程序可用。

我曾尝试在启动期间调用 SetProcessDPIAware(),但当它不起作用时,表明应用程序在其清单中是 DPI Aware。但是,这些措施都没有任何效果。

我用来指定 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>
</assembly>

【问题讨论】:

“manifest”和“assembly”听起来不像标准的 C++。您使用的是 C++/CLI 还是 C#?您应该正确地重新标记您的问题。 @ArneMertz,不幸的是,微软也为常规 C++ 制作了必要的清单。例如,这是获得 UAC 提升的方法。 @ArneMertz 程序集清单是标准的 Win32 并且从 Windows XP 开始使用,当时它允许主题化(除其他外),然后是 Vista/7,它指定了所需的权限和提升。 mackenir,这是视图还是对话框? @Deanna “需要计算标签定位”。确实——考虑到在 WTL 中实现这样的简单东西所需的努力,我不会打扰 :)。很遗憾,没有办法只说“Windows,请不要通过无能地尝试扩大我的 UI 来破坏我的 UI”... 【参考方案1】:

我在使用 SDL OpenGL 时遇到了类似的问题。在不知情的应用程序上进行 Windows DPI 缩放的实现非常糟糕,例如放大全屏视口和裁剪侧面。

我对清单没有任何运气。

我可以通过调用SetProcessDPIAware(); 来解决它,但它必须在 SDLmain 执行之前发生。也许您的“启动期间”还不够早。我将它用作main 函数之前的全局变量初始化器:

BOOL dpi_result = SetProcessDPIAware();

int main( int argc, char **argv )

    //...

【讨论】:

【参考方案2】:

对于 125% 的字体缩放,DPI 感知设置不相关。发生的情况是文本将大 25%,然后您有责任扩展您的 UI 以匹配。您的对话框通常需要大 25% 才能容纳更大的文本。您不仅需要缩放尺寸,还需要缩放位置。由你来编写所有这些代码。或者使用为您完成此任务的 UI 框架。

对于大于 125% 的字体缩放,DPI 感知设置开始发挥作用。会发生什么:

    如果您的应用未标记为 DPI 感知,Windows 将使用光栅图像调整大小来缩放您的应用。这将导致您的视觉元素被像素化。 如果您的应用被标记为 DPI 感知,Windows 将忠实地呈现您的应用。同样,您有责任调整 UI 以适应文本。

这个MSDN article拥有所有血腥细节。

回到您的具体问题。你说:

我想防止这种情况发生,这样文本就不会被放大,并且应用程序可以正确显示。

换句话说,您是说您想忽略用户的字体缩放设置并以 100% DPI 渲染,而不考虑他们的意愿。您可以通过将所有文本的大小减小 25% 来做到这一点。我真的不建议你这样做。

【讨论】:

对话框的大小通常不是以对话框单元为单位的吗,它已经基于字体大小了吗? 好点@Mark - 这应该放在答案中以使其更正确。 @David 回滚了我的修订,如果你想看看它在历史中。【参考方案3】:

这只是对在此问题上错误怀疑 MFC / Windows 7 的警告。

我遇到了同样的问题。我们的(较旧的)MFC 应用程序在 Windows 7 上运行且字体设置为 125% 时,以错误的大小显示对话框。控件被缩放,但每个对话框都小了大约 25%。

起初,我在对话框代码中搜索了可能设置其大小/位置的任何内容。然后我看到网上很多人在将MFC应用程序迁移到Windows 7时遇到对话框大小的问题,这增加了我对MFC/Windows 7的怀疑。

最后,我阅读了一个类似的讨论,发现 spy++ 的维护者评论说,它在退出时保存大小/位置的功能在字体/DPI 更改后强制窗口大小错误。我们的软件也在做同样的事情,但代码在主应用程序中,而不是在对话框中。

【讨论】:

【参考方案4】:

在我团队的应用程序中,我们在程序集属性而不是应用程序属性上具有 asmv3 的 xmlns 属性。

代替这一行:

<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>

这一行:

<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0' xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">

我获取了我产品的应用清单并将其剥离为仅父节点和父节点。供参考:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
  <asmv3:application>
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
      <dpiAware>true</dpiAware>
    </asmv3:windowsSettings>
  </asmv3:application>
</assembly>

【讨论】:

以上是关于设置高 DPI 时防止我的 Win32 应用程序的 UI 元素按比例放大的主要内容,如果未能解决你的问题,请参考以下文章

在 win32 应用程序中动态设置 DPI 感知级别

怎样进行Win10软件高DPI设置

win10 dpi设置是啥意思

Windows 应用程序 - DPI 问题

win10缩放影响鼠标dpi

启用 DPI Awareness 设置无效 (VisualStudio 2017)