29

给定 Win32 窗口的句柄,我需要找到它相对于其父窗口的位置。

我知道几个函数(例如;GetWindowRect()GetClientRect()),但它们都没有明确返回所需的坐标。

我该怎么做呢?

4

5 回答 5

44

解决方案是使用 和 的组合GetWindowRect()功率MapWindowPoints()

GetWindowRect()检索窗口相对于您在监视器上看到的整个屏幕区域的坐标。我们需要将这些绝对坐标转换为我们主窗口区域的相对坐标。将MapWindowPoints()相对于一个窗口给出的坐标转换为相对于另一个窗口的坐标。所以我们需要一个屏幕区域的“句柄”和我们试图找到坐标的控件的父窗口的句柄。屏幕是 Windows 术语中的“窗口”,称为“桌面”。HWND_DESKTOP我们可以通过定义的常量来访问Desktop的句柄WinUser.h(包括Windows.h就够了)。我们可以通过调用 Win32 函数来获取父窗口的句柄GetParent()。现在我们有了调用该MapWindowPoints()函数所需的所有参数。

RECT YourClass::GetLocalCoordinates(HWND hWnd) const
{
    RECT Rect;
    GetWindowRect(hWnd, &Rect);
    MapWindowPoints(HWND_DESKTOP, GetParent(hWnd), (LPPOINT) &Rect, 2);
    return Rect;
}

MapWindowPoints()定义为:

int MapWindowPoints(
  _In_     HWND hWndFrom,
  _In_     HWND hWndTo,
  _Inout_  LPPOINT lpPoints,
  _In_     UINT cPoints
);

MapWindowPoints()将坐标相对从 变换hWndFromhWndTo。在我们的例子中,我们进行从桌面(HWND_DESKTOP)到父窗口(GetParent(hWnd))的转换。因此,生成的RECT结构保存了我们的子窗口 ( hWnd) 相对于其父窗口的相对坐标。

于 2013-08-03T16:32:15.010 回答
15

这是我用于 Windows 或控件(子窗口)的解决方案

RECT rc;
GetClientRect(hWnd,&rc);
MapWindowPoints(hWnd,GetParent(hWnd),(LPPOINT)&rc,2);
于 2013-12-12T05:34:24.923 回答
4

我知道之前已经回答过了,但是在屏幕坐标中获取子窗口的矩形,获取它的位置(POINT ptCWPos = {rectCW.left, rectCW.top};)并使用该ScreenToClient()函数会容易得多,这会将屏幕坐标点转换为窗口的客户端坐标点:

PS:我知道这看起来像很多代码,但大部分都是在摆弄 rect 位置;在大多数情况下,实际上需要矩形位置而不是整个矩形。


HWND hwndCW, hwndPW; // the child window hwnd
                     // and the parent window hwnd
RECT rectCW;
GetWindowRect(hwndCW, &rectCW); // child window rect in screen coordinates
POINT ptCWPos = { rectCW.left, rectCW.top };
ScreenToClient(hwndPW, &ptCWPos); // transforming the child window pos
                                  // from screen space to parent window space
LONG iWidth, iHeight;
iWidth = rectCW.right - rectCW.left;
iHeight = rectCW.bottom - rectCW.top;

rectCW.left = ptCWPos.x;
rectCW.top = ptCWPos.y;
rectCW.right = rectCW.left + iWidth;
rectCW.bottom = rectCW.right + iHeight; // child window rect in parent window space

于 2019-12-15T06:41:32.747 回答
0

这是基于上述答案的非常基本的 typedef 结构:

typedef struct tagRectCl {
    static RECT rectOut;
    RECT RectCl(int ctrlID, HWND &hwndCtrl, HWND &ownerHwnd)
    {
    RECT rectIn;
    GetWindowRect(hwndCtrl, &rectIn); //get window rect of control relative to screen
    MapWindowPoints(NULL, ownerHwnd, (LPPOINT)&rectIn, 2);
    rectOut = rectIn;
    return rectOut;
    }
    RECT RectCl(int ctrlID)
    {
       // for rectOut already populated
       return rectOut;
    }
    };
}RectCl;

RECT RectCl::rectOut = {};

这个想法是将 ctrlID 扩展到一系列控件,其中rectOut可以考虑存储对应的 s 以获得更适应的结构。
用法:以下返回转换后的矩形:

RECT rect1 = RectCl().RectCl(IDC_CTRL1, hWndCtrl, hWndOwner);

以下是一个部分编码的函数,它将两个答案的元素转换为可用于对话的内容- 特别是对于移动/调整控制坐标,这是登陆此页面的原始原因。它接受来自资源或项目
的完整控件 ID 作为参数,以及其容器的句柄。 还应该考虑在调用函数之前是否通过监听in来最小化。HMENUCreateWindow
ownerHwndSIZE_MINIMIZEDWM_SIZE

BOOL ProcCtrl(int ctrlID, HWND ownerHwnd)
{
    RECT rcClient = {0};        
    HWND hwndCtrl = GetDlgItem(ownerHwnd, ctrlID);
    if (hwndCtrl)
    {
    GetWindowRect(hwndCtrl, &rcClient); //get window rect of control relative to screen
    MapWindowPoints(NULL, ownerHwnd, (LPPOINT)&rcClient,2);

    /* Set extra scaling parameters here to suit in either of the following functions
    if (!MoveWindow(hwndCtrl, rcClient.left, rcClient.top, 
    rcClient.right-rcClient.left, rcClient.bottom-rcClient.top, TRUE))
    {
        //Error;
        return FALSE;
    }
    //if (!SetWindowPos(hwndCtrl, NULL, (int)rcClient.left, (int)(rcClient.top),
    //(int)(rcClient.right - rcClient.left), (int)(rcClient.bottom - rcClient.top), SWP_NOZORDER))
    {
        //Error;
        //return FALSE;
    }
    }
    else
    {
        //hwndCtrl Error;
        return FALSE;
    }
    return TRUE;
}
于 2018-03-10T11:56:18.377 回答
0

更简单

BOOL CAuxFormView::OnInitDialog()
{
    // run the default
    CDialog::OnInitDialog();
    // define a rectangular
    CRect rc1;
    // get area of the control to the screen coordinates
    m_Viewer_Ctrl.GetWindowRect(rc1);
    // transform the screen coordinates relevant to the Dialog coordinates
    ScreenToClient(rc1);
    // move and refresh the control to the new area
    m_Viewer_Ctrl.MoveWindow(rc1);

}
于 2021-01-31T09:55:19.650 回答