How to eliminate flickering with erase background in mfc

1.9k Views Asked by At

I am working with SDI app to redraw graph and update data by using timer in View file. Even though I use ON_WM_ERASEBKGND to eliminate flickering, but it still happen. And below are my code that I tried to implement. Anyone has any ideas to eliminate flickering?

Here are my MSG_MAP

        ON_WM_PAINT()
    ON_WM_ERASEBKGND()
    ON_WM_TIMER()

        BOOL CVCDSOView::OnEraseBkgnd(CDC* pDC) 
        {
         // TODO: Add your message handler code here and/or call default
         return TRUE;
         return CView::OnEraseBkgnd(pDC);   
        }

        void CVCDSOView::OnInitialUpdate() 
        {
         CView::OnInitialUpdate();
         CRect Rect;
         GetClientRect(&Rect);
         CRect m_rcDraw = Rect;

             // set timer with 200ms
             SetTimer(ID_LABEL_COMPANY,200,NULL);

             labelCompany.Create(_T("Company"), WS_CHILD | WS_VISIBLE, 
        CRect(LEFT_SIDE, TOP_SIDE, RIGHT_SIDE+50, BOTTOM_SIDE), this, ID_LABEL_COMPANY);

         textboxCompany.Create(WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER | ES_NOHIDESEL, 
        CRect(LEFT_SIDE, TOP_SIDE+VERTICAL_OFFSET, RIGHT_SIDE+50, BOTTOM_SIDE+VERTICAL_OFFSET), this, ID_EDITTEXT_COMPANY);
        }
// CVCDSOView message handlers

        void CVCDSOView::OnPaint() 
        {
         CPaintDC dc(this); // device context for painting

         // TODO: Add your message handler code here
         CRect Rect;
         GetClientRect(&Rect);

         CDC dcMem;
         CBitmap bmpMem;
         dcMem.CreateCompatibleDC(&dc);
         bmpMem.CreateCompatibleBitmap(&dc,Rect.Width()- GRID_LEFT,Rect.Height()-35);
         dcMem.SelectObject(&bmpMem);
         dcMem.FillSolidRect(Rect, RGB(255,255,255));
         CRect m_rcDraw = Rect;
         m_rcDraw.DeflateRect(GRID_LEFT,GRID_TOP,GRID_RIGHT,GRID_BOTTOM);

             DrawGrid(&dcMem,m_rcDraw);

         dc.BitBlt(0,0,Rect.Width(),Rect.Height(),&dcMem,0,0,SRCCOPY);
         dcMem.DeleteDC();
         DeleteObject(bmpMem);
         // Do not call CView::OnPaint() for painting messages
        }

        void CVCDSOView::OnTimer(UINT nIDEvent) 
        {
         // TODO: Add your message handler code here and/or call default
         //
         if(nIDEvent==ID_LABEL_COMPANY)
         {
          CollectData();    
          Invalidate();
          CView::OnTimer(nIDEvent);
         }

        }

Any idea would be great appreciate.

2

There are 2 best solutions below

1
Barmak Shemirani On BEST ANSWER

You have child controls which can cause flicker when their background is painted. You want to exclude the child controls from paint area by adding WS_CLIPCHILDREN flag to the view class:

BOOL CVCDSOView::PreCreateWindow(CREATESTRUCT& cs)
{
    cs.style |= WS_CLIPCHILDREN;
    return CView::PreCreateWindow(cs);
}

Unrelated to flickering issue:

Don't subtract anything for main rectangle. You should change the bitmap to

bmpMem.CreateCompatibleBitmap(&dc, Rect.Width(), Rect.Height());

You don't need dcMem.DeleteDC() and DeleteObject(bmpMem) MFC will automatically delete these objects.

Note that MFC will not automatically de-select objects. This usually doesn't matter because Windows will do the necessary cleanup, as is done in this example. But for completeness sake add the following:

CBitmap* oldbitmap = (CBitmap*)dcMem.SelectObject(&bmpMem);
...
dc.BitBlt(0,0,Rect.Width(),Rect.Height(),&dcMem,0,0,SRCCOPY);
dcMem.SelectObject(oldbitmap);
4
Jovibor On
  1. In OnEraseBkgnd you should return FALSE.
  2. All drawing in OnPaint should better be done with CMemDC class, because drawing straight on the screen will most likely cause flickering as well:

    CMemDC memDC(*pDC, this);
    CDC& rDC = memDC.GetDC();
    rDC.ActualDrawing`...