在启用每个显示器缩放的应用程序中,子窗口是否与其父窗口具有相同的DPI?

3

可选的背景信息

一段时间以前,我提出了这个问题,其中具体讨论了文本大小和DLU,并且是在我没有意识到每个DPI感知实际意义的情况下提出的。然而,它并没有得到解决。很可能是因为我没有写一个清晰的问题,而是问了关于我的特定实现问题而不是由此引发的一般问题(“xX问题”)。

我提出这个问题是因为我正在编写一个动态GUI布局引擎——一个可以处理控件存在和可见性更改的引擎——并需要知道基础单位相对于哪个窗口。当时,我决定坐标应该基于父窗口,大小应该基于子窗口,但现在我意识到如果子窗口的DPI大于父窗口的DPI,这将会导致问题。

当然,这种类型的事情不仅仅限于DLU计算。例如,在垂直两半部分上绘制图片的窗口将不得不担心每个监视器DPI在中间发生变化。所以请允许我提出一般、明确的问题。


实际问题

今天我找到了这两篇MSDN文章:

阅读它们后,我现在对系统DPI感知有了以下认识:

  • PROCESS_SYSTEM_DPI_AWARE
    • 当要求某个东西的DPI时,系统将提供主监视器的DPI
    • 此值无法更改,并且因此不会在程序的生命周期内更改
    • 等同于调用旧版的SetProcessDPIAware()
  • PROCESS_DPI_UNAWARE
    • PROCESS_SYSTEM_DPI_AWARE类似,但DPI固定为96
  • PROCESS_PER_MONITOR_DPI_AWARE
    • 系统提供窗口所在监视器的DPI;当其更改时,将发送WM_DPICHANGED
    • 该消息页面说这也可能发生在监视器DPI更改时;我不知道现在你可以这样做

我想知道的是:

PROCESS_PER_MONITOR_DPI_AWARE的情况下,窗口的所有子窗口(非拥有窗口)的DPI是否与父窗口的DPI相同?

请注意超级级别:关于DPI在程序生命周期内不会改变的部分意味着对于其他两个感知值,答案是“是”。

另一个例子,假设我有一个300像素宽的窗口,其中有两个控件,每个控件都是100像素宽,在相反的边缘。如果我将该窗口拖动到两个具有不同DPI的监视器之间,使得一个控件在一个监视器上,另一个控件在另一个监视器上,然后查询它们的DPI(使用GetDC()GetDeviceCaps()),它们是否相同?

如果答案是肯定的,那么我就不需要担心在父窗口和子窗口之间转换坐标。

如果答案是否定的,那么下一个问题是WM_DPICHANGED是否发送到子窗口,还是只发送到顶层窗口?因为我仍然需要一种方法来知道子项的DPI何时更改,这样我至少可以尝试重新排列以使其看起来正确(我还没有想出如何做到这一点,这是另一个完全不同的问题,但我认为应该只是MulDiv())。

谢谢。


我尚未编写DPI感知的代码,一直想知道一个DPI感知的窗口如何处理跨越多个不同DPI的显示器的情况。 - Remy Lebeau
1个回答

3

当系统决定窗口的大部分已经跨到另一个显示器上时,顶级窗口将收到WM_DPICHANGED消息,并期望整个窗口根据新的DPI进行调整大小。

换句话说,系统不会尝试混合使用不同DPI的窗口。


因此,所有子级都具有顶层 DPI 的扩展。谢谢!(我想象那些手持窗口的人会惊讶于由于缩放而导致一半模糊的情况,但我不确定,因为我还没有高 DPI 显示器 :/) - andlabs
1
你不需要高DPI显示器来进行测试,只需要两个显示器。将其中一个调整到最高分辨率即可。虽然看起来有些傻,但你可以测试系统。 - David Heffernan
1
请考虑覆盖OP没有想到的情况,即上下文菜单。 - Hans Passant
@Hans 我不能说我自己想过那个问题。如果我必须猜测,我会认为系统从不将它们放置在两个监视器上。但是,当您用窗口跨越两个监视器,并在窗口上坐落于少数DPI的点处请求上下文菜单时,会发生什么呢? - David Heffernan
如果上下文菜单完全显示在一个监视器上,则获取该监视器的 DPI(而不是底层父级)。我猜想,如果您能够让上下文菜单跨越两个监视器,它将遵循相同的规则,并使用其中更多的监视器的 DPI。 - Jonathan Potter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接