14

我要解决的实际问题是,我想自动找出窗口周围边距的大小。如果您能找到更好的方法,请务必回答,而不是这个。

为此,我决定截取测试窗口的屏幕截图并测量边距。这很简单,因为我预计任何边距都不会是亮粉色,但我承认这是一个 hack。我使用GetWindowRect ( py ) 获取边界框,并使用PIL抓取屏幕截图并裁剪到边界框。问题是,虽然裁剪操作正确,但边界框并不准确。Windows 7“截图工具”的尺寸正确。我该怎么做?

4

6 回答 6

19

下面列出了我的第一个想法,但如果如您所述,您确定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));

那应该给你正确的边界矩形。

于 2010-07-07T06:00:27.593 回答
4

我知道这是一个有点老的话题。但是我花了很多时间搜索,我自己经历了 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()
于 2012-11-19T18:28:39.687 回答
2

如果窗口是在没有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 将返回正确的数据。唯一的缺点是当鼠标指针移到窗口框架上时,鼠标光标仍会变为调整大小的光标,但到目前为止它是较轻的。

于 2013-11-17T05:48:41.843 回答
1

DwmGetWindowAttribute

http://msdn.microsoft.com/en-us/library/aa969515%28VS.85%29.aspx

于 2010-07-07T06:11:46.240 回答
1

首先,调用 GetClientRect 检索客户矩形 R1,然后调用 AdjustWindowRectEx 根据 R1 计算准确的边界。

于 2010-07-07T07:54:08.790 回答
0

GetWindowRect 返回正确的值,但用于显式处理窗口。使用GetParent 函数获取父窗口的句柄,而 GetWindoWRect 为您返回最大 RECT 或 GetParent 返回值为 NULL。

于 2012-08-20T06:05:57.110 回答