屏幕上客户区矩形坐标

7

如何获取窗口客户区域相对于屏幕的坐标?

我考虑使用GetClientRectClientToScreen。另外,在浏览器窗口中,什么是ClientRect? 它只包括显示其中的HTML文档的矩形,还是包括可能缩小HTML文档尺寸的浏览器栏和弹出菜单?

我已经尝试了这个:

HWND hWnd;
RECT rc;
if (GetClientRect(hWnd, &rc)) // get client coords 
{
    MapWindowPoints(hWnd, NULL, reinterpret_cast<POINT*>(&rc), 2); // converts rect rc points
    return rc.top;
}

但是不幸的是,浏览器客户端矩形包括所有弹出式浏览器菜单和工具栏,因此无法用来检测浏览器HTML文档空间的准确坐标。如果有人有建议如何实现,我们将非常乐意尝试。

4个回答

15

是的,你可以使用ClientToScreen函数实现这个功能:

RECT rc;
GetClientRect(hWnd, &rc); // get client coords
ClientToScreen(hWnd, reinterpret_cast<POINT*>(&rc.left)); // convert top-left
ClientToScreen(hWnd, reinterpret_cast<POINT*>(&rc.right)); // convert bottom-right

"客户端"矩形在浏览器中的定义因浏览器实现而异。您可以使用Spy++自行查找。


4
注意,在从右向左的系统上返回一个无效的矩形。更好的方法是使用长度为2的 MapWindowPoints - Raymond Chen
1
变量rc周围的堆栈已经损坏,看起来你是对的,现在将尝试使用MapWindowPoints - Max Yari
3
我不知道RTL系统是什么,但是声明和使用一个单独的POINT结构而不是强制转换是否可以解决这个问题?这对我来说似乎能够很好地工作并且满足我的需求。 - AbePralle
1
@Ivanzinho ClientToScreen 函数适用于一个 POINT (x,y),而矩形由两个 POINTs (左上角,右下角) 组成。但是建议使用 Raymond Chen 提出的 MapWindowPoints 函数。 - Jonathan Potter
1
@Ivanzinho 这个 API 可能可以追溯到 1980 年代中期。当时 C 不支持返回结构体,我猜测这个 API 是围绕着这个限制设计的。 - Jonathan Potter
显示剩余3条评论

4
要将窗口的客户端矩形转换为屏幕坐标,请调用MapWindowPoints函数。它实现了特殊处理,即使在涉及带有从右到左布局的窗口的情况下,也始终返回有效的RECT

如果 hWndFromhWndTo(或两者都)是镜像窗口(即具有 WS_EX_LAYOUTRTL 扩展样式),并且传递了精确的两个点给 lpPoints,则 MapWindowPoints 将解释这两个点作为一个RECT,并可能自动交换该矩形的左右字段,以确保左侧不大于右侧。

相比之下,在两个点上调用ClientToScreen无法考虑RTL布局,并可能生成无效的RECT。它未遵循矩形坐标之一的不变式:

矩形右侧的坐标值必须大于其左侧。同样,底部的坐标值也必须大于顶部。

一个可靠的函数来返回窗口客户端矩形在屏幕坐标系下的情况如下:

RECT client_rect_in_screen_space(HWND const hWnd) {
    RECT rc{ 0 };
    if (!::GetClientRect(hWnd, &rc)) {
        auto const err_val{ ::GetLastError() };
        throw std::system_error(err_val, std::system_category());
    }

    ::SetLastError(ERROR_SUCCESS);
    if(::MapWindowPoints(hWnd, nullptr, reinterpret_cast<POINT*>(&rc), 2) == 0) {
        auto const err_val{ ::GetLastError() };
        if (err_val != ERROR_SUCCESS) {
            throw std::system_error(err_val, std::system_category());
        }
    }

    return rc;
}

问题更新要求解决不同、无关的问题。 系统中没有内置API,允许您查询Web浏览器显示区域的HTML内容。最有希望的解决方案是使用UI自动化。然而,这个问题太宽泛了,无法在此提供更详细的答案。


2

正如Raymond Chen所评论的那样,做这件事的首选方式应该是以下内容:

inline POINT get_client_window_position(const HWND window_handle)
{
    RECT rectangle;

    GetClientRect(window_handle, static_cast<LPRECT>(&rectangle));
    MapWindowPoints(window_handle, nullptr, reinterpret_cast<LPPOINT>(& rectangle), 2);

    const POINT coordinates = {rectangle.left, rectangle.top};

    return coordinates;
}

0
POINT origin;
origin.x = 0;
origin.y = 0;
ClientToScreen(hWnd, &origin);

现在,origin 是客户区左上角的屏幕坐标。

要将客户区坐标 (x,y) 转换为屏幕坐标,请添加 origin。 要进行相反操作,请减去。


正如雷蒙德·陈先生所指出的,这段代码片段会在RTL系统上引起问题,请不要使用它。 - user2120666
如果RTL表示从右到左,ScreenToClient可能会出现问题(https://msdn.microsoft.com/en-us/library/windows/desktop/dd162952(v=vs.85).aspx),但是ClientToScreen的文档没有提到这一点。 - Camille Goudeseune

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接