什么是抑制WM_ERASEBKGND的正确方法?

7
如果我需要使用双缓冲技术,我需要禁止WM_ERASEBKGND消息。
我可以处理WM_ERASEBKGND并立即返回。但是,我能否将WNDCLASS/WNDCLASSEXhbrBackground设置为NULL,而不处理WM_ERASEBKGND消息?这种方法正确吗?
2个回答

7
是的,将hbrBackground设置为NULL是避免实现无操作WM_ERASEBKGND处理程序的合适方式。
当您将WM_ERASEBKGND传递给DefWindowProc时,它会检查窗口类中的背景画刷。如果有一个,它会用它来填充脏区域。如果背景画刷为空,则不执行任何操作并返回。这基本上与拥有自己的无操作WM_ERASEBKGND处理程序相同。 WM_ERASEBKGND处理程序的返回值影响WM_PAINT调用BeginPaint时获取的PAINTSTRUCT结构体的fErase字段。WM_PAINT处理程序应检查fErase以确定它是否需要自行擦除背景,还是已由WM_ERASEBKGND完成。(尽管我从未看到过有人这样做。)如果让DefWindowProc处理WM_ERASEBKGND,则如果具有颜色号码或画刷,它将返回TRUE;如果hbrBackgroundNULL,则返回FALSE

2
请注意,即使如此,您仍然会收到 WM_ERASEBKGND。唯一的区别是如果您不处理它,什么也不会发生(可以安全地忽略)。 - Damon
你确定这是一个合适的方法吗?您知道为什么Raymond Chen好像区分使用NULL和空画刷吗? - jamesdlin
是的,这是合法的。MSDN关于hbrBackground的说明是:“当该成员为NULL时,应用程序必须在请求在其客户区域绘制时自行绘制其背景。” - Adrian McCarthy
@AdrianMcCarthy 我的意思是:您确定将 hbrBackground 设置为 NULL 且不处理 WM_ERASEBKGND(原始问题)是合适的吗?您引用的 MSDN 文档确实说“应用程序必须绘制自己的背景...”。(尽管您对我的答案的评论很有道理。) - jamesdlin
“...每当请求在其客户区域绘制时。” 这表明在 WM_PAINT 中执行是可以的。如果无效区域也标记为擦除,则 WM_ERASEBKGND 由 BeginPaint 调用发送,因此已在 WM_PAINT 处理程序中发生。为了确保理论与实践相符,我刚刚进行了测试。如果 hbrBackground 为 NULL,则 DefWindowProc 对 WM_ERASEBKGND 的处理是什么都不做,只返回 FALSE。 - Adrian McCarthy

1

我认为将hbrBackground = GetStockObject(HOLLOW_BRUSH)设置为更正确,而不是设置为NULL

《Raymond Chen的The Old New Thing》上的一篇文章进行了区分:

如果不希望自动绘制背景,则传递空刷。如果希望进行自定义背景绘制,则将画刷设为NULL

WNDCLASShbrBackground 成员的{{MSDN文档}}说:

当此成员为NULL时,应用程序必须在请求在其客户区域中绘制时自己绘制其背景。要确定是否必须绘制背景,应用程序可以处理WM_ERASEBKGND消息或测试由BeginPaint函数填充的PAINTSTRUCT结构体的fErase成员。

WM_ERASEBKGND的MSDN文档则表示:

DefWindowProc函数使用由WNDCLASS结构体中的hbrBackground成员指定的类背景画刷来擦除背景。如果hbrBackgroundNULL,应用程序应处理WM_ERASEBKGND消息并擦除背景。

我的理解是将hbrBackground设置为NULL,然后忽略处理WM_ERASEBKGND消息不是严格合法的(但可能有效);hbrBackground = NULL是一个承诺,你将自己处理WM_ERASEBKGND,而不让DefWindowProc尝试使用空指针绘制。


我认为你过于分析了。将hbrBackground设置为NULL可以做正确的事情。您可以通过处理WM_ERASEBKGND自己填充背景,也可以在WM_PAINT中完成。对于WM_ERASEBKGND,DefWindowProc返回TRUE如果指定了刷子(或颜色)并且填充了该区域,则返回FALSE如果hbrBackground为NULL。没有伤害。 - Adrian McCarthy
1
我认为区别在于从BeginPaint获取的PAINTSTRUCT中的fErase成员发生了什么。如果选择了空心画刷,则默认的WM_ERASEBKGND处理程序将使用空心画刷填充并返回TRUE(表示“我擦除了背景”)。这会导致fErase成员为FALSE,因此WM_PAINT处理程序的其余部分不会被欺骗而进行自己的擦除。如果选择了NULL,则默认的WM_ERASEBKGND处理程序不执行任何操作并返回FALSE(“我没有擦除背景”),这会导致fErase成员为TRUE。 - Adrian McCarthy
1
在PAINTSTRUCT的文档中,在fErase下面,它说:“如果创建窗口类时没有背景画刷,则应用程序负责擦除背景。” 因此,完全没有背景画刷是合法的。 这里,“应用程序”指的是WM_PAINT处理程序,因为当您从BeginPaint获取PAINTSTRUCT时,WM_ERASEBKGND已经过去了。 是的,您仍然需要负责绘制背景,但WM_PAINT处理程序是一个合法的地方来完成它。 - Adrian McCarthy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接