GetWindowRect слишком мал в Windows 7 - PullRequest
12 голосов
/ 07 июля 2010

Фактическая проблема, которую я пытаюсь решить, заключается в том, что я хочу автоматически определить размер полей вокруг окон. Если вы можете найти лучший способ, пожалуйста, ответьте, что вместо этого.

Для этого я решил сделать скриншот тестового окна и измерить поля. Это достаточно просто, так как я ожидаю, что поля не будут ярко-розовыми, но я признаю, что это взлом. Я использую GetWindowRect ( py ), чтобы получить ограничивающий прямоугольник, и PIL , чтобы получить скриншот и обрезать до ограничивающего прямоугольника. Проблема в том, что, хотя обрезка работает правильно, ограничивающая рамка не точна . Windows 7 «Snipping Tool» получает правильные размеры . Как я могу сделать то же самое?

Ответы [ 6 ]

18 голосов
/ 07 июля 2010

Мои первые мысли были перечислены ниже, но если, как вы утверждаете, вы уверены, что GetWindowRect возвращает неправильные значения, см. РАЗРЕШЕНИЕ далее.


"Что не так с GetSystemMetrics(SM_CXBORDER) и GetSystemMetrics(SM_CYBORDER)?

Метод, который вы используете, кажется очень окольным, и, если вы можете позвонить GetWindowRect(), я вполне уверен, что вы также можете вызвать GetSystemMetrics().

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

Это должно дать вам что-то вроде (100,200),(1000,900) и (112,227),(988,888) соответственно, и вы можете установить верхнюю границу как 227-200, нижнюю как 900-888, слева как 112-100 и справа как 900-888 (27,12,12,12).


Решение:

Небольшое расследование обнаруживает это . Это тема 2006 года, в которой говорится, что вы не можете получить правильные значения из GetWindowsRect. Тема, которая указала мне на это, гласила:

Приложения под Vista, которые не связаны с WINVER = 6, получат здесь вводящий в заблуждение набор значений, которые не учитывают дополнительное заполнение «стеклянных» пикселей, которые Vista Aero применяет к окну. Похоже, что это происходит даже в Aero Basic (без стекла), чтобы сохранить согласованность размеров. Обходной путь (если вы не хотите устанавливать WINVER = 6), по-видимому, заключается в том, чтобы динамически связываться с dwmapi.dll и использовать GetProcAddress () для получения функции DwmGetWindowAttribute () и вызывать ее с аргументом DWMWA_EXTENDED_FRAME_BOUNDS для запроса подлинного окна размеры рамы.

Так что, по сути, используйте что-то вроде (возможно, вам придется использовать ctypes, чтобы сделать это из Python):

RECT r;
HRESULT stat = DwmGetWindowAttribute (
    hwnd,
    DWMWA_EXTENDED_FRAME_BOUNDS,
    &r,
    sizeof(r));

и это должно дать вам правильный ограничивающий прямоугольник.

3 голосов
/ 19 ноября 2012

Я знаю, что это немного старая тема. Но это заняло довольно много времени, и я сам прошел через ctypes, чтобы получить решение paxdiablo, работающее на Python. Просто хотел поделиться рабочим примером кода для wxPython:

try:
    f = ctypes.windll.dwmapi.DwmGetWindowAttribute
except WindowsError:
    f = None
if f: # Vista & 7 stuff
    rect = ctypes.wintypes.RECT()
    DWMWA_EXTENDED_FRAME_BOUNDS = 9
    f(ctypes.wintypes.HWND(self.GetHandle()),
      ctypes.wintypes.DWORD(DWMWA_EXTENDED_FRAME_BOUNDS),
      ctypes.byref(rect),
      ctypes.sizeof(rect)
      )
    size = (rect.right - rect.left, rect.bottom - rect.top)        
else:      
    size = self.GetSize()
1 голос
/ 17 ноября 2013

GetWindowRect в Windows 7, по-видимому, не включает правый и нижний края рамки окна (по крайней мере, с помощью темы Aero afaik), , если окно было создано без стиль WS_SIZEBOX (т. е. вам нужно окно небольшого размера).

Проблема в том, что WS_SIZEBOX такой же, как WS_THICKFRAME, а в Aero окна имеют толстый кадр независимо от того, можно ли изменить их размер или нет.Но функция GetWindowRect считает, что окно без изменения размера тоньше.

Исправление?Вы можете создать окно с помощью WS_SIZEBOX, вызвать GetWindowRect, а затем использовать SetWindowLongPtr (GWL_STYLE, ...), чтобы отключить WS_SIZEBOX, но это создаст некрасивую белую границу внутри клиентской области.

Вместо этого оставьте WS_SIZEBOX включенным и просто верните одно и то же значение для ptMinTrackSize и ptMaxTraceSize в структуре MINMAXINFO при ответе на сообщение WM_GETMINMAXINFO.Это предотвратит изменение размера окна, и GetWindowRect вернет правильные данные.Единственным недостатком является то, что курсор мыши по-прежнему изменится на курсор изменения размера, когда указатель мыши переместится над рамкой окна, но пока это меньшее из зол.

1 голос
/ 07 июля 2010

Сначала вы вызываете GetClientRect, чтобы извлечь клиентский прямоугольник R1, затем вызываете AdjustWindowRectEx, чтобы вычислить точные границы в соответствии с R1.

1 голос
/ 07 июля 2010
0 голосов
/ 20 августа 2012

GetWindowRect возвращает правильные значения, но для явного дескриптора окна. Используйте функцию GetParent , чтобы получить дескриптор родительского окна, в то время как GetWindoWRect для вас возвращает максимальное значение RECT или GetParent, равное NULL.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...