可选的背景信息
一段时间以前,我提出了这个问题,其中具体讨论了文本大小和DLU,并且是在我没有意识到每个DPI感知实际意义的情况下提出的。然而,它并没有得到解决。很可能是因为我没有写一个清晰的问题,而是问了关于我的特定实现问题而不是由此引发的一般问题(“xX问题”)。
我提出这个问题是因为我正在编写一个动态GUI布局引擎——一个可以处理控件存在和可见性更改的引擎——并需要知道基础单位相对于哪个窗口。当时,我决定坐标应该基于父窗口,大小应该基于子窗口,但现在我意识到如果子窗口的DPI大于父窗口的DPI,这将会导致问题。
当然,这种类型的事情不仅仅限于DLU计算。例如,在垂直两半部分上绘制图片的窗口将不得不担心每个监视器DPI在中间发生变化。所以请允许我提出一般、明确的问题。
实际问题
今天我找到了这两篇MSDN文章:
- https://msdn.microsoft.com/en-us/library/windows/desktop/dn469266(v=vs.85).aspx
- https://msdn.microsoft.com/en-us/library/windows/desktop/mt744321(v=vs.85).aspx
阅读它们后,我现在对系统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更改时;我不知道现在你可以这样做
- 系统提供窗口所在监视器的DPI;当其更改时,将发送
我想知道的是:
在PROCESS_PER_MONITOR_DPI_AWARE
的情况下,窗口的所有子窗口(非拥有窗口)的DPI是否与父窗口的DPI相同?
请注意超级级别:关于DPI在程序生命周期内不会改变的部分意味着对于其他两个感知值,答案是“是”。
另一个例子,假设我有一个300像素宽的窗口,其中有两个控件,每个控件都是100像素宽,在相反的边缘。如果我将该窗口拖动到两个具有不同DPI的监视器之间,使得一个控件在一个监视器上,另一个控件在另一个监视器上,然后查询它们的DPI(使用GetDC()
和GetDeviceCaps()
),它们是否相同?
如果答案是肯定的,那么我就不需要担心在父窗口和子窗口之间转换坐标。
如果答案是否定的,那么下一个问题是WM_DPICHANGED
是否发送到子窗口,还是只发送到顶层窗口?因为我仍然需要一种方法来知道子项的DPI何时更改,这样我至少可以尝试重新排列以使其看起来正确(我还没有想出如何做到这一点,这是另一个完全不同的问题,但我认为应该只是MulDiv()
)。
谢谢。