如何在 Windows 对话框中处理 WM_ERASEBKGND 时避免闪烁
我有一个可以调整大小的对话框。 它还有一个自定义背景,我绘制该背景是为了响应 WM_ERASEBKGND 调用(当前是对 FillSolidRect 的简单调用)。
当调整对话框大小时,会发生巨大的闪烁。 为了尝试减少闪烁,我枚举了所有子窗口并将它们添加到剪切区域。 这似乎有点帮助——现在,当所有子控件重新绘制时,闪烁现象最为明显。
如何使对话框在调整大小时不闪烁? 我怀疑双缓冲必须发挥作用,但我不确定如何使用带有子控件的对话框来做到这一点(而不使所有子控件所有者绘制或类似的东西)。
我应该注意,我使用的是 C++(不是 .NET)和 MFC,尽管欢迎纯基于 Win32 的解决方案:)
注意:我尝试过但不起作用(不知道为什么)的一件事是:
CDC memDC;
memDC.CreateCompatibleDC(pDC);
memDC.FillSolidRect(rect, backgroundColor);
pDC->BitBlt(0, 0, rect.Width(), rect.Height(), &memDC, 0, 0, SRCCOPY);
I have a dialog that resizes. It also has a custom background which I paint in response to a WM_ERASEBKGND call (currently a simple call to FillSolidRect).
When the dialog is resized, there is tremendous flickering going on. To try and reduce the flickering I enumerate all child windows and add them to the clipping region. That seems to help a little -- now the flickering is mostly evident in all of the child controls as they repaint.
How can I make the dialog flicker-free while resizing? I suspect double-buffering must play a part, but I'm not sure how to do that with a dialog with child controls (without making all child controls owner-draw or something like that).
I should note that I'm using C++ (not .NET), and MFC, although pure Win32-based solutions are welcomed :)
NOTE: One thing I tried but which didn't work (not sure why) was:
CDC memDC;
memDC.CreateCompatibleDC(pDC);
memDC.FillSolidRect(rect, backgroundColor);
pDC->BitBlt(0, 0, rect.Width(), rect.Height(), &memDC, 0, 0, SRCCOPY);
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
假设“FillSolidRect”是背景的擦除,然后从 WM_ERASEBKGND 返回 TRUE。
要执行您几乎在代码片段中执行的双缓冲,您将需要使用 CreateCompatibleBitmap 并将其选择到您的 memDC 中。
Assuming that "FillSolidRect" is the erase of your background then return TRUE from the WM_ERASEBKGND.
To do the double buffering that you are almost doing in your code fragment, you will need to use CreateCompatibleBitmap and select that into your memDC.
尝试将以下行添加到 OnInitDialog 函数中:
Try adding the following line to your OnInitDialog function:
在 WM_ERASEBKGND 处理中不执行任何操作,并将擦除作为主 WM_PAINT 的一部分。 您可以更智能地绘制,以便仅重绘无效区域,或者更容易地对绘图进行双缓冲。
通过不在擦除背景中执行任何操作,您可以将所有绘图代码集中在一个位置,这将使其他人更容易遵循和维护。
Do nothing in the WM_ERASEBKGND handling and do the erase as part of your main WM_PAINT. You can either paint smarter so that you only redraw the invalid areas, or more easily, double-buffer the drawing.
By not doing anything in the erase background, you have all your drawing code in one location which should make it easier for others to follow and maintain.
如果您的目标是 WinXP 或更高版本,则还可以使用 WS_EX_COMPOSITED 样式,默认情况下为具有此样式的顶级窗口启用双缓冲。 请记住,这有其自身的一系列限制——具体来说,不再使用 GetDC 等从 OnPaint 周期中绘制。
If you are targeting WinXP or higher, you can also use the WS_EX_COMPOSITED style to enable double-buffering by default for top-level windows with this style. Bear in mind this has its own set of limitations -- specifically, no more drawing out of OnPaint cycles using GetDC, etc.
您可以将调用 InvalidateRect 方法的参数设置为 false。 这将阻止您在窗口重绘时发送 WM_ERASEBKGND。
you can set parameter of your call to InvalidateRect method as false. This will prevent you to send WM_ERASEBKGND when the window will redraw.
双缓冲确实是实现此目的的唯一方法。
只要您确保
CLIPCHILDREN
,子控件就会自行处理。Double buffering is indeed the only way to make this work.
Child controls will take care of themselves so long as you make sure
CLIPCHILDREN
.