VC防止視窗及其控制項(如CListCtrl)閃爍的簡單方法(一組有用的宏) 本文主要是通過網上一篇文章提供的解決辦法,整理了一組宏來實現防閃爍的。本文的重點是展示這個宏及其使用方法。 解決方案的原理請參考: 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在拉動時候的閃爍。