Как найти положение элемента управления Win32 по отношению к его родительскому окну?

Указанный дескриптор окна Win32, мне нужно найти его положение относительно его родительского окна.

Я знаю несколько функций (например, GetWindowRect() и GetClientRect()), но ни один из они явно возвращают требуемые координаты.

Как это сделать?

Ответ 1

Решение использует объединенную мощность GetWindowRect() и MapWindowPoints().

GetWindowRect() извлекает координаты окна относительно всей области экрана, которую вы видите на своем мониторе. Нам нужно преобразовать эти абсолютные координаты в относительные координаты нашей основной области окна. MapWindowPoints() преобразует координаты, заданные относительно одного окна, относительно другого. Поэтому нам нужен "дескриптор" области экрана и дескриптор родительского окна элемента управления, в котором мы пытаемся найти координаты. Экран - это "окно" в терминологии Windows, и он называется "Рабочий стол". Мы можем получить доступ к дескриптору Desktop постоянной константой HWND_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() преобразуют координаты относительно от hWndFrom до hWndTo. В нашем случае мы делаем преобразование из рабочего стола (HWND_DESKTOP) в родительское окно (GetParent(hWnd)). Поэтому результирующая структура RECT содержит относительные координаты нашего дочернего окна (hWnd) относительно его родительского окна.

Ответ 2

Это решение, которое я использую либо для окон, либо для элементов управления (дочерние окна)

RECT rc;
GetClientRect(hWnd,&rc);
MapWindowPoints(hWnd,GetParent(hWnd),(LPPOINT)&rc,2);

Ответ 3

Здесь функция, которая берет элементы обоих ответов во что-то полезное, особенно для управления перемещением/изменением координат.
Он принимает в качестве параметров интегральный идентификатор управления из ресурса и дескриптор его контейнера.
Следует также рассмотреть вопрос о том, минимизирован ли ownerHwnd до вызова функции, прослушивая SIZE_MINIMIZED в WM_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 scaling parameters 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;
}