本文主要是通过网上一篇文章提供的解决办法,整理了一组宏来实现防闪烁的。本文的重点是展示这个宏及其使用方法。 解决方法的原理请参考: http://www.cndes.cn/Designs/Program/200608052716.html
针对上文中提到的 “有效的进行搽除" 方法整理如下:
原文作者的思路是复写WM_ERASEBKGND消息处理函数OnEraseBkgnd,
只对空白区域使用指定背景色重绘。而对已经有控件的区域,不做重绘,从而
避免窗口及其控件闪烁。
上述方法确实有效,但在有很多控件的情况下,计算一个窗口中需要擦除并重绘的”空白区域“
是一件很麻烦的事情。为了方便这种方法的实际应用,我写了一组宏来完成”计算空白区域“的功能:
/***********************************************************************************************************/
/************************************************************************/
/* 宏功能: 界面刷新时仅刷新指定控件以外的空白区域;可有效避免窗口闪烁
/* 使用于: 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在拉动时候的闪烁。
使用宏防止闪烁
最新推荐文章于 2024-10-17 17:10:02 发布