C++:在MFC应用程序中使用WM_ERASEBKGND-Message避免闪烁



在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。

在一个渲染窗口内容花费大量时间的应用程序中,我采取了以下步骤:

  1. 当屏幕需要重新绘制时,从位图中闪电式地显示其内容
  2. 如果底层数据发生了更改,请启动一个线程,将该数据渲染到一个新的位图中(如果该线程已经在运行,只需设置一个标志)
  3. 渲染线程完成后,将存储的位图与线程结果交换,并使窗口无效(如果设置了according标志,则立即重新启动渲染)
  4. 调整窗口大小时,触发渲染并将位图展开到窗口
  5. 当视图滚动时,blit那些可用的部分并触发渲染

重要的好处不仅是你没有闪烁,而且当应用程序中的线程忙于将数据渲染成图形时,它还能保持响应。在实现中,除了常见的多线程问题外,还有一些重要的事情:

  • 不要同时在后台运行多个线程,因为这会降低性能。如果你只是用鼠标拉伸窗口,你可以很容易地生成几十条调整大小的消息,你既不想为此浪费时间也不想浪费内存
  • 只渲染可见部分,就像滚动视图的虚拟大小一样,位图可能会变得非常大。为了使滚动更容易,您可以添加一个帧(例如,宽度/高度的五分之一),以在后台准备新位图时保持一些额外的数据可用

最新更新