使非客户区无效

Posted

技术标签:

【中文标题】使非客户区无效【英文标题】:Invalidating non-client areas 【发布时间】:2011-02-18 16:21:27 【问题描述】:

我有一个具有自定义边框/标题的窗口,为此我处理 WM_NCPAINT 消息。我的标题有两个背景,一个用于活动窗口的较亮背景,一个用于背景窗口的较暗背景。

但在某些情况下,例如当窗口失去/获得焦点时,我的标题没有更新,所以我以错误的背景结束。

到目前为止,我已经处理了 WM_NCACTIVATE,并发送了 RedrawWindow(hwnd, NULL, NULL, RDW_FRAME|RDW_INVALIDATE),但这会导致整个窗口重新绘制。您对此有什么建议吗?

【问题讨论】:

【参考方案1】:

覆盖非客户区总是充满危险。窗口管理器似乎为优化做了很多假设。显然它可以完成,请参阅 Office,但可能需要大量实验。

只是一个想法。调用 RedrawWindow 两次,一次使非客户区无效,然后再次使客户区有效。

RedrawWindow(hwnd, NULL, NULL, RDW_FRAME | RDW_INVALIDATE);
RedrawWindow(hwnd, NULL, NULL, RDW_NOFRAME | RDW_VALIDATE);

另一个想法是尝试立即仅绘制框架,而不会使任何内容无效:

RedrawWindow(hwnd, NULL, NULL, RDW_FRAME | RDW_UPDATENOW | RDW_NOCHILDREN);

还有一个想法是在第二个或第三个参数中指定一个空的 RECT 或 HREGION。这样可能不会使客户区无效。

【讨论】:

我尝试使用 VALIDATE 标志,但没有按预期工作。当需要更新某些子控件时,VALIDATE 将阻止这种情况。最后我做了类似于你的第二个建议的事情,我传递了一个区域,它是窗口矩形减去客户端矩形,这些似乎适用于矩形窗口但不适用于非矩形窗口,这很好对我来说足够了。 我相信RDW_VALIDATE 的意思是第二行的RDW_INVALIDATE @Paul:不,我打算RWD_VALIDATE。我想我没有足够清楚地解释我的假设。框架失效似乎使整个窗口失效。所以我猜然后验证客户区只会使非客户区无效。无论如何,伊斯梅尔的评论说这并没有解决问题。起作用的是最后一个关于提供空 RECT 或 HREGION 的建议。【参考方案2】:

其实这样就行了:

SetWindowPos(hwnd, 0, 0, 0, 0, 0,
    SWP_DRAWFRAME|SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|SWP_NOZORDER);

【讨论】:

这样做实际上有很多开销。在 Spy++ 中使用 SetWindowPos()RedrawWindow(hwnd, NULL, NULL, RDW_FRAME | RDW_INVALIDATE); 观看它,后者只是发送一个 WM_NCPAINT,而前者发送如果窗口被移动/调整大小会发生的所有消息。

以上是关于使非客户区无效的主要内容,如果未能解决你的问题,请参考以下文章

Invalidate()函数

Invalidate() InvalidateRect() 与 UpdateWindow()

MFC中窗口刷新函数详解

MFC中的Invalidate、OnDraw、OnPaint函数的作用、区别和联系?

MFC中窗口刷新函数详解

c ++ mfc非客户区包含其他窗口吗