在多个显示监视器上定位对象

位于多个监视器上的窗口或菜单会导致查看者的视觉中断。 为了尽量减少此问题,系统会在一个监视器上显示菜单和新的窗口和最大化窗口。 下表显示了如何选择监视器。

Object 位置
window CreateWindow (Ex) 在包含窗口最大部分的监视器上显示一个窗口。在最小化之前,在包含窗口最大部分的监视器上最大化窗口。
Alt-TAB 组合键在具有当前活动窗口的监视器上显示一个窗口。
拥有的窗口 与其所有者位于同一监视器上。
显示在包含相应菜单项最大部分的监视器上。
上下文菜单 显示在发生右键单击的监视器上。
下拉列表 (drop-down list) 显示在包含组合框矩形的监视器上。
“事实检索器” 对话框 显示在拥有它的窗口的监视器上。如果它是使用DS_CENTERMOUSE样式定义的,则它通过鼠标显示在监视器上。
如果它没有所有者,并且活动窗口且对话框位于同一应用程序中,则该对话框将显示在当前活动窗口的监视器上。
如果对话框没有所有者,并且活动窗口与对话框不在同一应用程序中,则对话框将显示在主监视器上。
消息框 显示在拥有它的窗口的监视器上。

 

如果窗口跨越两个监视器,并且其中一个监视器被重新定位,系统会将窗口放置在包含原始窗口最大部分的监视器上。

应用程序通常还需要定位对象。 例如,可能需要在与另一个窗口相同的监视器上创建一个窗口。

在多个监视系统上定位对象

  1. 确定适当的监视器。
  2. 获取监视器的坐标。
  3. 使用坐标定位对象。

通常,将对象定位在主监视器上,或定位在已有对象的监视器上。 若要标识给定点、矩形或窗口的监视器,请使用 MonitorFromPointMonitorFromRectMonitorFromWindow

若要获取监视器的坐标,请使用 GetMonitorInfo,它同时提供工作区和整个监视器矩形。 请注意,SM_CXSCREEN和SM_CYSCREEN始终引用主监视器,而不一定是指显示应用程序的监视器。 此外,请避免SM_xxVIRTUALSCREEN,因为这会将窗口放在虚拟屏幕上,而不是监视器上。

若要使对话框在窗口工作区中居中,请使用DS_CENTER样式。 若要将对话框居中指向应用程序窗口,请使用 GetWindowRect。 Windows 自动将菜单和对话框限制为监视器。 但是,自定义菜单、自定义下拉框、自定义工具面板和保存的应用程序位置可能存在问题。

有关如何正确定位对象的示例,请参阅 在多显示器设置上定位对象

使用SM_CXSCREEN和SM_CYSCREEN来确定应用程序桌面工具栏的位置 (也称为 appbar) 将应用栏限制为主监视器。 若要允许应用栏位于任何监视器的任何边缘,请使用适当的系统指标来计算监视器的边缘。 此外,使用 GET_X_LPARAMGET_Y_LPARAM 宏提取坐标,否则坐标的符号可能不正确。 这些宏包含在 Windowsx.h 中。

全屏窗口的大小需要更改,因为它在具有不同分辨率的监视器之间移动。 为此,应用程序必须使用 MonitorFromWindowMonitorFromPoint 检查它位于哪个窗口,然后使用 GetMonitorInfo 获取监视器的大小。 作为替代方法,可以使用 DirectX DirectDrawEnumerateEx 函数中的 HMONITOR。 然后使用 SetWindowPos 定位窗口并调整其大小,以覆盖监视器。

最大化窗口不涵盖具有“始终位于顶部”属性的任务栏。 但是,全屏窗口覆盖任务栏,例如,在 Microsoft PowerPoint 幻灯片放映和游戏中。

若要保存和稍后还原应用程序退出时窗口的位置,请使用 GetWindowPlacementSetWindowPlacement 函数。 但是,检查该位置在使用之前仍然有效,因为监视器可能已从系统中移动或删除。 如果窗口的 HMONITOR 无效,应用程序将在主监视器上显示窗口。

系统尝试在包含其快捷方式的监视器上启动应用程序。 因此,定位应用程序的一种方法是在所需的监视器上设置其快捷方式。

如果使用 ShellExecuteShellExecuteEx, 请提供 hWnd ,以便系统将在调用应用程序所在的同一监视器上打开任何新窗口。

请注意,对于具有多个监视器的系统, MINMAXINFO 结构的值会略有更改。