【发布时间】:2021-07-22 00:53:51
【问题描述】:
我正在努力使 MFC 应用程序在具有不同 DPI 缩放比例的多个监视器环境中正确显示。当主显示器和辅助显示器以不同的 DPI 运行并且应用位于辅助显示器上时,我无法解释一个问题。
如果主显示器具有 100% DPI 缩放 (96) 而辅助显示器具有相同的 100% DPI 缩放,则一切正常。
如果主监视器具有 100% DPI 缩放 (96) 而辅助监视器具有 125% 缩放 (120 DPI) 或 150% 缩放 (144 DPI) 或任何其他更高的值,当子窗口最大化时,部分子窗口系统栏可见,如下所示:
如果您仔细观察,125% 的 7 个像素和 150% 的 14 个像素。假设系统栏在 100% 缩放时为 29 个像素,在 150% 时为 36 和 125%,以及 43 个像素,这 7 和 14 个像素分别是 125% 和 150% 时栏大小与 100% 时的高度差基线。
因此,条形图的位置和大小似乎是由系统在主监视器上运行时计算的。
当你最大化子窗口时,会有一系列Windows消息发送到窗口:WM_GETMINMAXINFO > WM_WINDOWPOSCHANGING > WM_GETMINMAXINFO > WM_NCCALSIZE > WM_WINDOWSPOSCHANGED > WM_MOVE > @987654333 @。 WM_GETMINMAXINFO 当窗口的大小或位置即将改变时发送,以便应用程序可以覆盖,例如,窗口的默认最大化大小和位置。对此有一个注释:
对于具有多个监视器的系统,ptMaxSize 和 ptMaxPosition 成员描述窗口的最大化大小和位置 主监视器,即使窗口最终最大化到 辅助监视器。在这种情况下,窗口管理器会调整这些 值来补偿主监视器和 显示窗口的监视器。因此,如果用户离开 ptMaxSize untouched,显示器上比主窗口大的窗口 监视器最大化到较大监视器的大小。
Raymond Chan 有一篇文章对此进行了解释:How does the window manager adjust ptMaxSize and ptMaxPosition for multiple monitors?。
所以ptMaxSize 应该填充主显示器的尺寸。我的主显示器是 2560x1440 像素,辅助显示器的尺寸是 1920x1200。但是,我在这里得到的尺寸值是 1757x1023 和 1761x1027(在连续调用时)。这既不是主监视器的大小,也不是辅助监视器的大小。
我试图做一个肮脏的把戏并处理WM_NCCALCSIZE 消息并将位置(左,上)设置为0(相对于父级)。
void CMyMDIChildWnd::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp)
{
CMDIChildWnd::OnNcCalcSize(bCalcValidRects, lpncsp);
if (condition)
{
lpncsp->rgrc[0].left = 0;
lpncsp->rgrc[0].top = 0;
}
}
只要子窗口有焦点就可以正常工作。如果我单击另一个窗口并且它失去焦点,则该栏将重新绘制并显示在先前的位置。这个技巧只是说客户区从哪里开始,所以当非客户区被重绘时,我会回到原来的问题。
我的问题是这个问题的根源是什么,我该如何解决?
【问题讨论】:
-
编写 MFC 应用程序的方法有很多种。无论有或没有每显示器高 DPI 感知设置和两个不同的显示器,我都不会重现标准 MFC 模板的任何问题。但是你的带有 2 个图标的蓝色“丝带”看起来并不标准。你有复制代码/项目吗?
-
不,我没有可重现的代码。我制作了一个 MDI MFC 应用程序,最大化子窗口效果很好。我的应用程序的 UI 是完全定制的。但这并不是那么特别。蓝色条是菜单栏,它下面是工具栏。我没有截取整个窗口,只截取了相关部分。
-
很抱歉我无法构建项目来重现您的问题,所以我仍然希望您能提供一个可重现的示例。也许你可以参考this可能相关的线程。
-
我猜你对 主窗体的非客户区处理有一些问题。
-
实际上,主框架不处理
WM_NCPAINT消息和其他非客户端消息(WM_PAINT和WM_ERASEBKGND都不处理)。那里没什么大不了的。
标签: c++ winapi visual-c++ mfc dpi-aware