如何确定窗口是否在屏幕外?

时间:2011-01-13 15:26:30

标签: c++ windows winapi css-position multiple-monitors

在Windows XP及更高版本中,给定一个窗口句柄(HWND),如何判断窗口位置和大小是否会使窗口无法恢复到屏幕外?例如,如果标题栏可用于光标,则可以将窗口拖回屏幕。我需要发现窗口是否实际可见或至少对用户可用。我想我还需要知道如何检测和响应分辨率变化以及如何处理多个监视器。这似乎是一个相当大的交易。我正在使用C ++和常规SDK,因此请限制您对该平台的回答,而不是调用C#或类似的。

3 个答案:

答案 0 :(得分:18)

Windows使得在主监视器上确定用户工作区域的大小(即,未被任务栏遮挡的屏幕区域)变得相对简单。调用 SystemParametersInfo function并为第一个参数(SPI_GETWORKAREA)指定 uiAction 标志。 pvParam参数应指向RECT structure,它将在虚拟屏幕坐标中接收工作区域的坐标。

一旦你获得了描述工作区域的坐标,就可以将它们与应用程序窗口的当前位置进行比较,以确定它是否位于这些边界内。


支持多个监视器的愿望使事情稍微复杂一些。 SystemParametersInfo的文档建议您需要调用GetMonitorInfo function来获取除主数据库之外的监视器的工作区域。它填充了一个名为MONITORINFOEX的结构,其中包含定义该监视器工作区域的成员rcWork,再次以虚拟屏幕坐标表示为RECT结构。

要做到这一点,您需要枚举用户连接到系统的所有监视器,并使用GetMonitorInfo检索每个监视器的工作区域。

互联网上有一些这样的样本:

  • MSDN有一些Positioning Objects on a Multiple Display Setup的示例代码。
  • 如果你正在使用MFC,那么这就是多监视器支持的an excellent example
  • 即使您没有使用MFC,该文章也会引用the following link,它看起来是一个真正的宝石,只要解释多个显示器支持如何在Windows中运行,即使它有点旧学校。无论喜欢与否,在Windows的更高版本中,这一点都没有改变。


最后,您提到要检测分辨率更改。这比你想象的要简单得多。如您所知,如果您已完成任何Windows编程,则操作系统与您的应用程序通信的主要方式是向WindowProc function发送消息。
在这种情况下,您需要注意WM_DISPLAYCHANGE message,当显示分辨率发生变化时,会发送到所有窗口。 wParam包含每像素位数的新图像深度; lParam的低位字指定水平分辨率,lParam的高位字指定屏幕的垂直分辨率。

答案 1 :(得分:3)

您可以使用MonitorFromRect或MonitorFromPoint检查窗口的左上角或右下角是否包含在任何显示器中(屏幕外)。

POINT p;
p.x = x;
p.y = y;
HMONITOR hMon = MonitorFromPoint(p, MONITOR_DEFAULTTONULL);
if (hMon == NULL) {
    // point is off screen
}

答案 2 :(得分:0)

可见性检查非常简单。

RECT rtDesktop, rtView;

GetWindowRect( GetDesktopWindow(), &rtDesktop );
GetWindowRect( m_hWnd, &rtView );

HRGN rgn = CreateRectRgn( rtDesktop.left, rtDesktop.top, rtDesktop.right, rtDesktop.bottom );

BOOL viewIsVisible = RectInRegion( rgn, &rtView );

DeleteObject(rgn);

您不必使用RectInRegion,我用它来缩短代码。

如果您处理WM_SETTINGCHANGE消息,显示,分辨率更改监控也很容易。

http://msdn.microsoft.com/en-us/library/ms725497(v=vs.85).aspx

<强>更新

正如@Cody Gray所说,我认为WM_DISPLAYCHANGE比WM_SETTINGCHANGE更合适。但是MFC 9.0库使用了WM_SETTINGCHANGE。