如何在mfc中用擦除背景消除闪烁

How to eliminate flickering with erase background in mfc

我正在使用 SDI 应用程序通过在视图文件中使用计时器来重绘图形和更新数据。即使我使用 ON_WM_ERASEBKGND 来消除闪烁,但它仍然会发生。下面是我尝试实现的代码。谁有消除闪烁的想法?

这是我的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);
         }

        }

任何想法将不胜感激。

  1. OnEraseBkgnd 你应该 return FALSE.
  2. OnPaint中的所有绘图最好用CMemDCclass完成,因为直接在屏幕上绘图很可能也会导致闪烁:

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

您的子控件在绘制背景时可能会导致闪烁。您想要通过向视图 class:

添加 WS_CLIPCHILDREN 标志来从绘画区域中排除子控件
BOOL CVCDSOView::PreCreateWindow(CREATESTRUCT& cs)
{
    cs.style |= WS_CLIPCHILDREN;
    return CView::PreCreateWindow(cs);
}

与闪烁问题无关:

不要为主矩形减去任何内容。您应该将位图更改为

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

不需要dcMem.DeleteDC()并且DeleteObject(bmpMem)MFC会自动删除这些对象。

请注意,MFC 不会自动取消 select 对象。这通常无关紧要,因为 Windows 将进行必要的清理,如本例中所做的那样。但为了完整起见,添加以下内容:

CBitmap* oldbitmap = (CBitmap*)dcMem.SelectObject(&bmpMem);
...
dc.BitBlt(0,0,Rect.Width(),Rect.Height(),&dcMem,0,0,SRCCOPY);
dcMem.SelectObject(oldbitmap);