我在 C++/MFC 应用程序中使用 GDI+,每当调整窗口大小时,我似乎都无法避免闪烁。
我已经尝试过以下步骤:
- 返回 TRUE
OnEraseBkGnd()
;
- 返回 NULL
OnCtlColor()
;
- 根据此代码使用双缓冲:
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);
}
难道我做错了什么?或者还有其他方法可以实现这一目标吗?
要完全避免闪烁,您需要完成all在屏幕更新之间的间隔中绘制。 Windows 没有提供任何简单的方法来完成正常的窗口绘制(Vista 通过DWM https://en.wikipedia.org/wiki/Desktop_Window_Manager,但即使在运行 Vista 的系统上也不能依赖这一点)。因此,要尽量减少闪烁,最好的办法就是尽快绘制所有内容(reduce通过增加在刷新周期内完成所有绘制的机会来避免撕裂),并避免过度绘制(绘制屏幕的一部分,然后在顶部绘制其他内容:存在向用户呈现部分绘制的屏幕的风险)。
让我们讨论一下到目前为止所介绍的技术:
-
不执行任何操作 OnEraseBkgnd():通过防止窗口的无效区域被窗口的背景颜色填充来帮助避免过度绘制。当您在 WM_PAINT 处理期间再次绘制整个区域时很有用anyway,就像双缓冲绘图的情况一样...但请参阅通过防止在 WM_PAINT 方法之后进行绘图来避免过度绘制的注释。
-
OnCtlColor() 返回 NULL: 这实际上不应该做anything...除非您的表单上有子控件。在这种情况下,请参阅关于通过防止在 WM_PAINT 方法之后进行绘制来避免过度绘制的注释。
-
双缓冲绘图:通过将实际的屏幕绘图减少到单个,有助于避免撕裂(也可能是过度绘制)BitBLT https://en.wikipedia.org/wiki/Bit_blit。但可能会影响绘图所需的时间:无法使用硬件加速(尽管使用 GDI+,使用任何硬件辅助绘图的机会非常小),每次重绘都必须创建并填充离屏位图,并且每次重绘都必须重新绘制整个窗口。看高效双缓冲的注意事项.
-
对 BitBlt 使用 GDI 调用而不是 GDI+:这通常是个好主意 -Graphics::DrawImage()
可能会很慢。我什至找到了正常的GDIBitBlt() https://msdn.microsoft.com/en-us/library/dd183370.aspx在某些系统上调用速度更快。尝试一下这个,但前提是先尝试一些其他建议。
-
避免在每次调整大小时强制完全重绘的窗口类样式(CS_VREDRAW、CS_HREDRAW):这会有帮助,但前提是你不这样做need当大小改变时重画整个窗口。
有关通过在 WM_PAINT 方法之前防止绘制来避免过度绘制的注意事项
当窗口的全部或部分失效时,它将被擦除并重新绘制。如前所述,如果您打算重新绘制整个无效区域,则可以跳过擦除。However,如果您正在使用子窗口,则必须确保父窗口不会同时擦除您的屏幕区域。应在所有父窗口上设置 WS_CLIPCHILDREN 样式 - 这将防止在子窗口(包括您的视图)占用的区域上进行绘制。
有关通过在 WM_PAINT 方法之后防止绘制来避免过度绘制的注意事项
如果你有any如果您的窗体上托管有子控件,您将需要使用 WS_CLIPCHILDREN 样式来避免在它们上绘制(并随后被它们过度绘制)。请注意,这会在一定程度上影响 BitBlt 例程的速度。
高效双缓冲的注意事项
现在,每次视图自行绘制时,您都会创建一个新的后台缓冲区图像。对于较大的窗口,这可能表示正在分配和释放大量内存,并且will导致严重的性能问题。我建议在视图对象中保留动态分配的位图,并根据需要重新分配它以匹配视图的大小。
请注意,在调整窗口大小时,这将导致与当前系统一样多的分配,因为每个新大小都需要分配一个新的后台缓冲区位图来匹配它 - 您可以通过向上舍入尺寸来稍微减轻痛苦到 4、8、16 等的下一个最大倍数,这样您就可以避免在大小的每个微小变化上重新分配。
请注意,如果自上次渲染到后台缓冲区以来窗口的大小没有更改,则在窗口失效时无需重新渲染它 - 只需将已渲染的图像移出到屏幕。
另外,分配与屏幕位深度匹配的位图。构造函数为Bitmap
您当前使用的默认为 32bpp、ARGB 布局;如果这与屏幕不匹配,则必须对其进行转换。考虑使用GDI方法CreateCompatibleBitmap() https://msdn.microsoft.com/en-us/library/dd183488.aspx以获得匹配的位图。
最后...我假设您的示例代码只是一个说明性片段。但是,如果您实际上除了将现有图像渲染到屏幕上之外什么都不做,那么您实际上根本不需要维护后台缓冲区 - 只需直接从图像进行 Blt(并提前将图像的格式转换为与屏幕匹配)。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)