visual-c++timermfconpaint

How to eliminate flickering with erase background in mfc


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.


Solution

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