最近在网上看到一个就是关于VC防止窗口和控件闪烁的方法!
/***********************************************************************************************************/
/************************************************************************/
/* 宏功能: 界面刷新时仅刷新指定控件以外的空白区域;可有效避免窗口闪烁
/* 使用于: WM_ERASEBKGND 消息处理函数 OnEraseBkgnd(); 
/************************************************************************/
#define ERASE_BKGND_BEGIN \
    CRect bgRect;\
    GetWindowRect(&bgRect);\
    CRgn bgRgn;\
    bgRgn.CreateRectRgnIndirect(bgRect);
//#define ERASE_BKGND_BEGIN// Marco parameter 'IDC' specifies the identifier of the control 
#define ADD_NOERASE_CONTROL(IDC)\
{\
    CRect controlRect;\
    GetDlgItem(IDC)->GetWindowRect(&controlRect);\
    CRgn controlRgn;\
    controlRgn.CreateRectRgnIndirect(controlRect);\
    if(bgRgn.CombineRgn(&bgRgn, &controlRgn, RGN_XOR)==ERROR)\
        return false;\
}// Marco parameter 'noEraseRect' specifies a screen coordinates based RECT, 
// which needn't erase.
#define ADD_NOERASE_RECT(noEraseRect)\
{\
    CRgn noEraseRgn;\
    noEraseRgn.CreateRectRgnIndirect(noEraseRect);\
    if(bgRgn.CombineRgn(&bgRgn, &noEraseRgn, RGN_XOR)==ERROR)\
        return false;\
}// Marco parameter 'pDC' is a kind of (CDC *) type.
// Marco parameter 'clBrushColor' specifies the color to brush the area.
#define ERASE_BKGND_END(pDC, clBrushColor)\
    CBrush brush;\
    brush.CreateSolidBrush(clBrushColor);\
    CPoint saveOrg = (pDC)->GetWindowOrg();\
    (pDC)->SetWindowOrg(bgRect.TopLeft());\
    (pDC)->FillRgn(&bgRgn, &brush);\
    (pDC)->SetWindowOrg(saveOrg);\
    brush.DeleteObject();\
//#define ERASE_BKGND_END
/***********************************************************************************************************/
说明:
1)宏 ERASE_BKGND_BEGIN 和 ERASE_BKGND_END(pDC, clBrushColor) 搭配使用。
2)宏 ADD_NOERASE_CONTROL(IDC) 和 ADD_NOERASE_RECT(noEraseRect) 根据需要放在上面两个宏的中间,用来添加不需要重绘背景的区域(正是这些区域导致了闪烁),使用次数不限。其中参数noEraseRect是一个屏幕坐标系的RECT类型或CRect类型。使用举例1:
在当前窗体的类中重写WM_ERASEBKGND消息处理函数如下:
BOOL CMyWnd::OnEraseBkgnd(CDC* pDC) 
{
    ERASE_BKGND_BEGIN;
    ADD_NOERASE_RGN(IDC_BUTTON2);
    ADD_NOERASE_RGN(IDC_BUTTON1);
    ADD_NOERASE_RGN(IDC_LIST_STAT);
    ERASE_BKGND_END(pDC, GetSysColor(COLOR_3DFACE));
    return false;
}
上面的IDC_BUTTON2,IDC_BUTTON1,IDC_LIST_STAT即窗体上的控件。
你可以指定其他已存在的控件。
这样,窗口在擦除背景时,将只对上述控件以后的”空白区域“使用系统色重绘,有效避免了闪烁。备注:
    重载WM_ERASEBKGND消息处理函数OnEraseBkgnd的方法, 
     选择View->ClassWizard->classinfo选项卡:message filter下拉框:
   选择window,然后再选择message maps选项卡,在messages下拉框应该可以找到
   wm_erasebkgnd.双击添加.使用举例2:防止CListCtrl在拉动窗口时闪烁。/* * No further full-erasing is required,  * to prevent screen flashing caused by background erase and view repaint. * Only erase the blank area. */BOOL CExListCtrl::OnEraseBkgnd(CDC* pDC) { //compute the holding-data-items area of this list control CRect rect; CPoint dataRgnTopLeftPoint; CPoint dataRgnBottomRightPoint; GetItemPosition(0 , &dataRgnTopLeftPoint); GetItemPosition(GetItemCount() , &dataRgnBottomRightPoint); if(!GetHeaderCtrl()->GetItemRect(GetHeaderCtrl()->GetItemCount()-1, rect))  return CListCtrl::OnEraseBkgnd(pDC); dataRgnBottomRightPoint.x = rect.right; rect.SetRect(dataRgnTopLeftPoint, (CPoint)(dataRgnBottomRightPoint - CPoint(2,2))); ClientToScreen(dataRgnRect);  //compute and erase the blank area. Using the Marco. ERASE_BKGND_BEGIN; ADD_NOERASE_RECT(dataRgnRect); ERASE_BKGND_END(pDC, GetBkColor()); return false;}说明:CListCtrl在拉动的时候,会前以背景色重刷背景,再在上面绘制有数据的Items,      而没有数据的区域则保持背景色。因此,如果在BOOL CExListCtrl::OnEraseBkgnd(CDC* pDC)       函数中简单的return false,那么没有数据的区域将显示不正常。          故举例2中先计算出有数据的items的区域,这是不需要以背景重刷的区域。      再使用本文的宏,就可以有效避免CListCtrl在拉动时候的闪烁。但是我不懂就是要把他写的宏放在什么位置???还是每个界面都要加OnEraseBKgnd()?最主要的就是想解决我的列表框中的数据刷新闪烁问题!

解决方案 »

  1.   

    BOOL CExListCtrl::OnEraseBkgnd(CDC* pDC) 
    {

    //举例2中先计算出有数据的items的区域,这是不需要以背景重刷的区域。 再使用本文的宏,就可以有效避免CListCtrl在拉动时候的闪烁。
    }文中已经提到使用方法了,就是创建一个自己的列表框类CExListCtrl,在该类中重载OnEraseBkgnd函数,在函数里面计算有数据的items的区域。再使用宏。不知楼主是不是这个意思?
      

  2.   

    应该是写到OnDraw()或者OnPaint中吧
      

  3.   

    楼主,你的列表刷新不是双缓存和OnEraseBk问题,你刷新的问题应该是在于,你每次把数据写入都是把原表青空,然后再把数据重新写入.这个是导致你闪烁的主要原因.
    解决方法是:找到你列表的索引,修改索引对应的值