在多个显示监视器上定位对象
位于多个监视器上的窗口或菜单会导致查看者的视觉中断。 为了尽量减少此问题,系统会在一个监视器上显示菜单和新的窗口和最大化窗口。 下表显示了如何选择监视器。
Object | 位置 |
---|---|
window |
CreateWindow (Ex) 在包含窗口最大部分的监视器上显示一个窗口。在最小化之前,在包含窗口最大部分的监视器上最大化窗口。 Alt-TAB 组合键在具有当前活动窗口的监视器上显示一个窗口。 |
拥有的窗口 | 与其所有者位于同一监视器上。 |
子 | 显示在包含相应菜单项最大部分的监视器上。 |
上下文菜单 | 显示在发生右键单击的监视器上。 |
下拉列表 (drop-down list) | 显示在包含组合框矩形的监视器上。 |
“事实检索器” 对话框 | 显示在拥有它的窗口的监视器上。如果它是使用DS_CENTERMOUSE样式定义的,则它通过鼠标显示在监视器上。 如果它没有所有者,并且活动窗口且对话框位于同一应用程序中,则该对话框将显示在当前活动窗口的监视器上。 如果对话框没有所有者,并且活动窗口与对话框不在同一应用程序中,则对话框将显示在主监视器上。 |
消息框 | 显示在拥有它的窗口的监视器上。 |
如果窗口跨越两个监视器,并且其中一个监视器被重新定位,系统会将窗口放置在包含原始窗口最大部分的监视器上。
应用程序通常还需要定位对象。 例如,可能需要在与另一个窗口相同的监视器上创建一个窗口。
在多个监视系统上定位对象
- 确定适当的监视器。
- 获取监视器的坐标。
- 使用坐标定位对象。
通常,将对象定位在主监视器上,或定位在已有对象的监视器上。 若要标识给定点、矩形或窗口的监视器,请使用 MonitorFromPoint、 MonitorFromRect 和 MonitorFromWindow。
若要获取监视器的坐标,请使用 GetMonitorInfo,它同时提供工作区和整个监视器矩形。 请注意,SM_CXSCREEN和SM_CYSCREEN始终引用主监视器,而不一定是指显示应用程序的监视器。 此外,请避免SM_xxVIRTUALSCREEN,因为这会将窗口放在虚拟屏幕上,而不是监视器上。
若要使对话框在窗口工作区中居中,请使用DS_CENTER样式。 若要将对话框居中指向应用程序窗口,请使用 GetWindowRect。 Windows 自动将菜单和对话框限制为监视器。 但是,自定义菜单、自定义下拉框、自定义工具面板和保存的应用程序位置可能存在问题。
有关如何正确定位对象的示例,请参阅 在多显示器设置上定位对象。
使用SM_CXSCREEN和SM_CYSCREEN来确定应用程序桌面工具栏的位置 (也称为 appbar) 将应用栏限制为主监视器。 若要允许应用栏位于任何监视器的任何边缘,请使用适当的系统指标来计算监视器的边缘。 此外,使用 GET_X_LPARAM 和 GET_Y_LPARAM 宏提取坐标,否则坐标的符号可能不正确。 这些宏包含在 Windowsx.h 中。
全屏窗口的大小需要更改,因为它在具有不同分辨率的监视器之间移动。 为此,应用程序必须使用 MonitorFromWindow 或 MonitorFromPoint 检查它位于哪个窗口,然后使用 GetMonitorInfo 获取监视器的大小。 作为替代方法,可以使用 DirectX DirectDrawEnumerateEx 函数中的 HMONITOR。 然后使用 SetWindowPos 定位窗口并调整其大小,以覆盖监视器。
最大化窗口不涵盖具有“始终位于顶部”属性的任务栏。 但是,全屏窗口覆盖任务栏,例如,在 Microsoft PowerPoint 幻灯片放映和游戏中。
若要保存和稍后还原应用程序退出时窗口的位置,请使用 GetWindowPlacement 和 SetWindowPlacement 函数。 但是,检查该位置在使用之前仍然有效,因为监视器可能已从系统中移动或删除。 如果窗口的 HMONITOR 无效,应用程序将在主监视器上显示窗口。
系统尝试在包含其快捷方式的监视器上启动应用程序。 因此,定位应用程序的一种方法是在所需的监视器上设置其快捷方式。
如果使用 ShellExecute 或 ShellExecuteEx, 请提供 hWnd ,以便系统将在调用应用程序所在的同一监视器上打开任何新窗口。
请注意,对于具有多个监视器的系统, MINMAXINFO 结构的值会略有更改。