我在C++/MFC应用程序中使用GDI +,但无论何时调整窗口大小,我似乎都无法避免闪烁。
我已经尝试了以下步骤:
OnEraseBkGnd()
上返回TRUE; OnCtlColor()
上返回NULL; void vwView::OnDraw(CDC* pDC)
{
CRect rcClient;
GetClientRect(rcClient);
Bitmap bmp(rcClient.Width(), rcClient.Height());
Graphics graphics(&bmp);
graphics.DrawImage(m_image, rcClient.left, rcClient.top);
Graphics grph(pDC->m_hDC);
grph.DrawImage(&bmp, 0, 0);
}
难道我做错了什么?还是有另一种方法来实现这一目标?
最佳答案
为了完全避免闪烁,您需要在屏幕更新之间的间隔内完成所有绘图。 Windows没有提供任何简单的方法来完成普通的窗口绘制(Vista通过DWM提供了合成图,但是即使在运行Vista的系统上也不能依靠它)。因此,最小化闪烁的最佳方法是尽快绘制所有内容(通过增加刷新周期内完成所有绘制的机会来减少撕裂),并避免过度绘制(绘制屏幕的一部分,然后再绘制其他内容)最上方:可能会向用户展示部分绘制的屏幕)。
现在让我们讨论这里介绍的技术:
Graphics::DrawImage()
可能很慢。我什至发现在某些系统上,正常的GDI BitBlt()
调用速度更快。尝试一下,但只有先尝试其他一些建议后才能尝试。关于通过防止在WM_PAINT方法之前进行绘制来避免 overdraw 的注意事项
当窗口的全部或一部分无效时,它将被擦除并重新绘制。如前所述,如果您打算重新粉刷整个无效区域,则可以跳过擦除。 但是,如果您正在使用子窗口,则必须确保父窗口不会同时擦除屏幕区域。应该在所有父窗口上设置WS_CLIPCHILDREN样式-这将防止在子窗口(包括您的 View )上绘制区域。
关于通过在WM_PAINT方法之后防止绘制来避免 overdraw 的注意事项
如果您的窗体上托管有任何子控件,则您将希望使用WS_CLIPCHILDREN样式来避免对其进行绘制(并随后被它们过度绘制。请注意,这会在一定程度上影响BitBlt例程的速度。
关于高效双缓冲的注意事项
现在,每次 View 绘制时都会创建一个新的后缓冲图像。对于较大的窗口,这可能表示分配和释放了大量内存,并且将导致严重的性能问题。我建议在 View 对象中保留一个动态分配的位图,并根据需要重新分配它以匹配 View 的大小。
请注意,在调整窗口大小时,这将导致与当前系统一样多的分配,因为每个新大小都需要分配一个新的后缓冲区位图来匹配它-您可以通过向上舍入尺寸来减轻痛苦扩展到4、8、16等的下一个最大倍数,这样您就可以避免在每次微小更改时重新分配。
请注意,如果自上次渲染到后缓冲区以来窗口的大小没有改变,则在窗口无效时无需重新渲染它-只需将已经渲染的图像弹出到屏幕。
另外,分配与屏幕的位深度匹配的位图。您当前使用的
Bitmap
的构造函数将默认为32bpp,ARGB布局;如果与屏幕不匹配,则必须进行转换。考虑使用GDI方法 CreateCompatibleBitmap()
获得匹配的位图。最后...我假设您的示例代码就是这样,是一个说明性代码段。但是,如果您实际上除了在屏幕上渲染现有图像外什么也不做,那么您根本不需要维护后台缓冲区-只需直接从图像中进行Blt(并将图像格式提前转换为匹配屏幕)。
关于c++ - 使用GDI +和C++减少闪烁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/197948/