windows 如何确定窗口是否在屏幕外?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4681738/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I determine if a window is off-screen?
提问by hatcat
In Windows XP and above, given a window handle (HWND), how can I tell if the window position and size leaves the window irretrievably off screen? For example, if the title bar is available to the cursor, then the window can be dragged back on screen. I need to discover if the window is in fact visible or at least available to the user. I guess I also need to know how to detect and respond to resolution changes and how to deal with multiple monitors. This seems like a fairly big deal. I'm using C++ and the regular SDK, so please limit your answers to that platform rather than invoking C# or similar.
在 Windows XP 及更高版本中,给定一个窗口句柄 (HWND),如何判断窗口位置和大小是否使窗口无法挽回地离开屏幕?例如,如果标题栏对光标可用,则可以将窗口拖回到屏幕上。我需要发现窗口实际上是否可见或至少对用户可用。我想我还需要知道如何检测和响应分辨率变化以及如何处理多个显示器。这似乎是一件相当大的事情。我正在使用 C++ 和常规 SDK,因此请将您的答案限制在该平台上,而不是调用 C# 或类似的。
回答by Cody Gray
Windows makes it relatively simple to determine the size of a user's working area on the primary monitor (i.e., the area of the screen not obscured by the taskbar). Call the SystemParametersInfo
functionand specify the SPI_GETWORKAREA
flag for the first parameter (uiAction
). The pvParam
parameter should point to a RECT
structurethat will receive the coordinates of the working area in virtual screen coordinates.
Windows 使得在主监视器上确定用户工作区域的大小(即未被任务栏遮挡的屏幕区域)变得相对简单。调用该函数并为第一个参数 ( )指定标志。该参数应指向一个结构,该结构将接收虚拟屏幕坐标中工作区的坐标。SystemParametersInfo
SPI_GETWORKAREA
uiAction
pvParam
RECT
Once you've got the coordinates that describe the working area, it's a simple matter of comparing those to the current position of your application's window to determine if it lies within those bounds.
获得描述工作区域的坐标后,将这些坐标与应用程序窗口的当前位置进行比较以确定它是否在这些范围内是一件简单的事情。
The desire to support multiple monitors makes things slightly more complicated. The documentation for SystemParametersInfo
suggests that you need to call the GetMonitorInfo
functioninstead to get the working area of a monitor other than the primary. It fills in a structure called MONITORINFOEX
that contains the member rcWork
that defines the working area of that monitor, again expressed in virtual screen coordinates as a RECT
structure.
支持多台显示器的愿望使事情变得稍微复杂一些。的文档SystemParametersInfo
建议您需要调用该GetMonitorInfo
函数来获取除主监视器之外的监视器的工作区域。它填充一个名为的结构MONITORINFOEX
,其中包含rcWork
定义该监视器工作区域的成员,再次以虚拟屏幕坐标表示为一个RECT
结构。
To do this right, you'll need to enumerate all of the monitors a user has connected to the system and retrieve the working area of each using GetMonitorInfo
.
要正确执行此操作,您需要枚举用户已连接到系统的所有监视器,并使用GetMonitorInfo
.
There are a few samples of this to be found around the Internet:
在 Internet 上可以找到一些这样的示例:
- MSDN has some sample code for Positioning Objects on a Multiple Display Setup.
- If you're using MFC, here's what looks to be an excellent exampleof multiple monitor support.
- Even if you're not using MFC, that article refers the following linkwhich looks be a real gem as far as explaining how multiple monitor supports works in Windows, even if it's a little bit old school. Like it or not, very little of this has changed in later versions of Windows.
- MSDN 有一些用于在多显示器设置上定位对象的示例代码。
- 如果您使用的是 MFC,这里看起来是多显示器支持的一个很好的例子。
- 即使您不使用 MFC,该文章也引用了以下链接,该链接看起来是一个真正的宝石,它解释了 Windows 中多显示器支持的工作原理,即使它有点老派。不管喜欢与否,在更高版本的 Windows 中,这一点几乎没有改变。
Finally, you mentioned wanting to detect resolution changes. This is much simpler than you probably imagined. As you know if you've done any Windows programming, the primary way that the operating system communicates with your application is by sending messages to your WindowProc
function.
In this case, you'll want to watch for the WM_DISPLAYCHANGE
message, which is sent to all windows when the display resolution has changed. The wParam
contains the new image depth in bits per pixel; the low-order word of the lParam
specifies the horizontal resolution and the high-order word of the lParam
specifies the vertical resolution of the screen.
最后,您提到想要检测分辨率变化。这可能比您想象的要简单得多。如您所知,如果您做过任何 Windows 编程,操作系统与您的应用程序进行通信的主要方式是向您的WindowProc
函数发送消息。
在这种情况下,您需要注意在显示分辨率改变时发送到所有窗口的WM_DISPLAYCHANGE
消息。所述wParam
包含在每个像素的位数的新的图像的深度; 的低位字lParam
指定lParam
屏幕的水平分辨率,高位字指定屏幕的垂直分辨率。
回答by Evgeny
You can use MonitorFromRect or MonitorFromPoint to check if window's top left point or bottom right point isn't contained within any display monitor (off screen).
您可以使用 MonitorFromRect 或 MonitorFromPoint 检查窗口的左上点或右下点是否不包含在任何显示监视器(屏幕外)中。
POINT p;
p.x = x;
p.y = y;
HMONITOR hMon = MonitorFromPoint(p, MONITOR_DEFAULTTONULL);
if (hMon == NULL) {
// point is off screen
}
回答by 9dan
Visibility check is really easy.
能见度检查非常简单。
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);
You don't have to use RectInRegion, I used for shorten code.
您不必使用 RectInRegion,我用于缩短代码。
Display, resolution change monitoring is also easy if you handle WM_SETTINGCHANGE message.
如果您处理 WM_SETTINGCHANGE 消息,显示、分辨率更改监控也很容易。
http://msdn.microsoft.com/en-us/library/ms725497(v=vs.85).aspx
http://msdn.microsoft.com/en-us/library/ms725497(v=vs.85).aspx
UPDATE
更新
As @Cody Gray noted, I think WM_DISPLAYCHANGE is more appropriate than WM_SETTINGCHANGE. But MFC 9.0 library make use of WM_SETTINGCHANGE.
正如@Cody Gray 指出的那样,我认为 WM_DISPLAYCHANGE 比 WM_SETTINGCHANGE 更合适。但是 MFC 9.0 库使用了 WM_SETTINGCHANGE。