GetWindowRect слишком мал для Windows 7
Фактическая проблема, которую я пытаюсь решить, - это автоматическое определение размера полей вокруг окон. Если вы можете найти лучший способ, пожалуйста, обязательно ответьте, что вместо этого.
Для этого я решил снять скриншот тестового окна и измерить его. Это достаточно просто, так как я ожидаю, что никакие поля никогда не будут ярко-розовыми, но я признаю это взломом. Я использую GetWindowRect (py), чтобы получить ограничивающий и PIL, чтобы захватить скриншот и обрезать рамку. Проблема в том, что пока растение работает правильно, ограничивающий прямоугольник нечетный. Windows 7 "Snipping Tool" получает правильные размеры. Как я могу сделать то же самое?
Ответы
Ответ 1
Мои первые мысли были перечислены ниже, но если, как вы заявляете, вы уверены, что 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).
Решение:
Немного исследований появляется this. Это поток от 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));
и это должно дать вам правильный ограничивающий прямоугольник.
Ответ 2
Я знаю, что это немного старая тема. Но это заняло немало времени, и я сам стал страдать от 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()
Ответ 3
DwmGetWindowAttribute
http://msdn.microsoft.com/en-us/library/aa969515%28VS.85%29.aspx
Ответ 4
сначала вы вызываете GetClientRect для извлечения клиентского прямоугольника R1,
затем вызовите функцию AdjustWindowRectEx для вычисления точных границ в соответствии с R1.
Ответ 5
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 вернет правильные данные. Единственный недостаток заключается в том, что курсор мыши по-прежнему будет меняться на курсор изменения размера, когда указатель мыши перейдет через оконный фрейм, но это пока что меньше зла.
Ответ 6
GetWindowRect возвращает правильные значения, но для явного дескриптора окна. Используйте функцию GetParent, чтобы получить дескриптор родительского окна, в то время как GetWindoWRect возвращает для вас максимальное значение RECT или GetParent - значение NULL.