viertro
viertro

Reputation: 173

C++: Avoid flickering using WM_ERASEBKGND-Message in MFC-Application

in the OnDraw()-Method i create a Bitmap and blit it to the output every time the window size changes:

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);
}

But every time the application needs to recreate the bitmap in OnDraw(), the Screen gets white until it blits the bitmap to the screen. How can i use the WM_ERASEBKGND-Message to avoid this flickering?

Upvotes: 0

Views: 1731

Answers (2)

Ulrich Eckhardt
Ulrich Eckhardt

Reputation: 17444

In an application where rendering the window content took nontrivial amounts of time I took the following steps:

  1. when the screen needs a redraw, blit its content from a bitmap
  2. if the underlying data changes, kick off a thread to render that data into a new bitmap (if that thread is already running, just set a flag)
  3. when the rendering thread finishes, exchange the stored bitmap with the thread result and invalidate the window (if the according flag is set, restart rendering right away)
  4. when the window is resized trigger rendering and stretch-blit the bitmap to the window
  5. when the view is scrolled, blit those parts that are available and trigger rendering

The important benefit is not just that you don't have flickering, but also that the application remains responsive while a thread in it is busy rendering the data into a graphic. In the implementation, apart from the usual multithreading issues, there are a few important things:

  • Don't run multiple threads in the background at once, as that can degrade performance. If you just stretch the window with the mouse you can easily generate tens of resize messages and you neither want to waste the time nor the amount of memory for that.
  • Only render the visible parts, as with virtual sizes of a scrollview the bitmap can become really large. In order to make scrolling easier you can add a frame (e.g. 1/5th of the width/height) to keep some additional data available while preparing a new bitmap in the background.

Upvotes: 1

Lukas Thomsen
Lukas Thomsen

Reputation: 3207

I don't know with MFC but with the native Windows API you have to process the WM_ERASEBKGND message and simply return TRUE;. This tells the default window procedure that the message is processed hence the window background is erased. As a result the flickering disappears.

Additionally if you're using function InvalidateRect(..) be sure to set parameter bErase to FALSE. Note that the parameter is TRUE by default if not explicitly given.

Upvotes: 3

Related Questions