在OnDraw()-方法中,我创建一个位图,并在每次窗口大小更改时将其闪电传输到输出:
void CmbmView::OnDraw(CDC* pDC)
{
CRect WindowSize;
HDC hdc;
BITMAPINFO pbmi;
HBITMAP hbm;
CBitmap *pBitmap;
CDC MemDC;
void* ppvBits;
GetClientRect(WindowSize);
hdc = CreateDC (TEXT ("DISPLAY"), NULL, NULL, NULL) ;
memset(&pbmi, 0, sizeof(BITMAPINFO));
pbmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pbmi.bmiHeader.biWidth = WindowSize.Width();
pbmi.bmiHeader.biHeight = -WindowSize.Height(); // top down
pbmi.bmiHeader.biPlanes = 1;
pbmi.bmiHeader.biBitCount = 32;
pbmi.bmiHeader.biCompression = BI_RGB;
hbm = CreateDIBSection(hdc, &pbmi, DIB_RGB_COLORS, &ppvBits, NULL, NULL);
pBitmap = CBitmap::FromHandle(hbm);
MemDC.CreateCompatibleDC(pDC);
MemDC.SelectObject(pBitmap);
// "Draw" into ppvBits
GetDocument()->DrawApple(pDC, ppvBits, WindowSize.Width(), WindowSize.Height(), m_MaxIter, m_MaxBetragQuadrat, m_BW);
// Blit it to the output
pDC->BitBlt(0, 0, WindowSize.Width(), WindowSize.Height(), &MemDC, 0, 0, SRCCOPY);
}
但每当应用程序需要在OnDraw()中重新创建位图时,屏幕都会变白,直到它将位图闪电式传输到屏幕。如何使用WM_ERASEBKGND-消息来避免这种闪烁?
我不知道使用MFC,但使用本机Windows API时,您必须处理WM_ERASEBKGND
消息,只需处理return TRUE;
。这告诉默认窗口过程消息已被处理,因此窗口背景将被擦除。结果,闪烁消失了。
此外,如果使用函数InvalidateRect(..)
,请确保将参数bErase
设置为FALSE
。请注意,如果未明确给定,则默认情况下参数为TRUE。
在一个渲染窗口内容花费大量时间的应用程序中,我采取了以下步骤:
- 当屏幕需要重新绘制时,从位图中闪电式地显示其内容
- 如果底层数据发生了更改,请启动一个线程,将该数据渲染到一个新的位图中(如果该线程已经在运行,只需设置一个标志)
- 渲染线程完成后,将存储的位图与线程结果交换,并使窗口无效(如果设置了according标志,则立即重新启动渲染)
- 调整窗口大小时,触发渲染并将位图展开到窗口
- 当视图滚动时,blit那些可用的部分并触发渲染
重要的好处不仅是你没有闪烁,而且当应用程序中的线程忙于将数据渲染成图形时,它还能保持响应。在实现中,除了常见的多线程问题外,还有一些重要的事情:
- 不要同时在后台运行多个线程,因为这会降低性能。如果你只是用鼠标拉伸窗口,你可以很容易地生成几十条调整大小的消息,你既不想为此浪费时间也不想浪费内存
- 只渲染可见部分,就像滚动视图的虚拟大小一样,位图可能会变得非常大。为了使滚动更容易,您可以添加一个帧(例如,宽度/高度的五分之一),以在后台准备新位图时保持一些额外的数据可用