我要解决的实际问题是,我想自动找出窗口周围边距的大小。如果您能找到更好的方法,请务必回答,而不是这个。
为此,我决定截取测试窗口的屏幕截图并测量边距。这很简单,因为我预计任何边距都不会是亮粉色,但我承认这是一个 hack。我使用GetWindowRect ( py ) 获取边界框,并使用PIL抓取屏幕截图并裁剪到边界框。问题是,虽然裁剪操作正确,但边界框并不准确。Windows 7“截图工具”的尺寸正确。我该怎么做?
下面列出了我的第一个想法,但如果如您所述,您确定GetWindowRect
返回的值不正确,请参阅下面的RESOLUTION。
“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(不带 Glass)中似乎也会发生这种情况,以保持尺寸一致性。解决方法(如果你不想设置 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));
那应该给你正确的边界矩形。
我知道这是一个有点老的话题。但是我花了很多时间搜索,我自己经历了 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()
如果窗口是在没有WS_SIZEBOX 样式的情况下创建的(即,您想要一个非大小的窗口),Windows 7 上的 GetWindowRect 似乎不包括右侧和底部窗口框架边缘(至少使用 Aero 主题 afaik )。
问题是,WS_SIZEBOX 与 WS_THICKFRAME 相同,并且在 Aero 上,无论是否可以调整大小,窗口都有粗框。但是 GetWindowRect 函数认为不可调整大小的窗口更薄。
修复?您可以使用 WS_SIZEBOX 创建窗口,调用 GetWindowRect,然后使用 SetWindowLongPtr(GWL_STYLE, ...) 关闭 WS_SIZEBOX,但这会在客户区内创建一个难看的白色边框。
相反,保持启用 WS_SIZEBOX,并在响应 WM_GETMINMAXINFO 消息时简单地为 MINMAXINFO 结构中的 ptMinTrackSize 和 ptMaxTraceSize 返回相同的值。这将使窗口无法调整大小,并且 GetWindowRect 将返回正确的数据。唯一的缺点是当鼠标指针移到窗口框架上时,鼠标光标仍会变为调整大小的光标,但到目前为止它是较轻的。
DwmGetWindowAttribute
http://msdn.microsoft.com/en-us/library/aa969515%28VS.85%29.aspx
首先,调用 GetClientRect 检索客户矩形 R1,然后调用 AdjustWindowRectEx 根据 R1 计算准确的边界。
GetWindowRect 返回正确的值,但用于显式处理窗口。使用GetParent 函数获取父窗口的句柄,而 GetWindoWRect 为您返回最大 RECT 或 GetParent 返回值为 NULL。