當(dāng)我們需要在用戶區(qū)顯示一些圖形時(shí),先把圖形在客戶區(qū)畫上,雖然已經(jīng)畫好但此時(shí)我們還無法看到,還要通過程序主動(dòng)地刷新用戶區(qū),強(qiáng)制Windows發(fā)送一條WM_PAINT消息,這將引發(fā)視類OnDraw函數(shù)簡(jiǎn)單地將所有的圖形對(duì)象重畫,這樣才完成了圖形的顯示工作,但在刷新的同時(shí)會(huì)引起較明顯的閃爍尤其是當(dāng)畫面面積較大、圖像元素過多時(shí)尤為明顯甚至達(dá)到無法正常工作的地步。因此,我們需要做相應(yīng)的處理。本文介紹了采用先在內(nèi)存中繪制圖形,然后再把繪好的圖形以位圖方式從內(nèi)存拷貝到窗口客戶的消除刷屏閃爍的一種方法。
WM_PAINT消息和無效區(qū)
·在用戶移動(dòng)窗口或顯示窗口時(shí),窗口中先前被隱藏的區(qū)域重新可見。
·用戶改變窗口的大小。
·滾動(dòng)窗口用戶區(qū)。
·程序調(diào)用InvalidateRect或InvalidateRgn函數(shù)顯式地發(fā)送一條WM_PAINT消息。
當(dāng)上面情況之一發(fā)生時(shí),就要求應(yīng)用程序一定刷新其用戶區(qū)的一部分或全部,Windows會(huì)向窗口函數(shù)發(fā)送一條WM_PAINT消息。另外,當(dāng)Windows刪除覆蓋窗口部分區(qū)域的對(duì)話框或消息框時(shí)和菜單下拉出來又被釋放時(shí)窗口用戶區(qū)被臨時(shí)覆蓋,系統(tǒng)會(huì)試圖保存顯示區(qū)域,但是不一定能成功,可能向窗口函數(shù)發(fā)送一條WM_PAINT消息,要求應(yīng)用程序刷新其用戶區(qū)。需要說明的是:光標(biāo)或圖符穿過窗口用戶區(qū)時(shí),也可能覆蓋顯示內(nèi)容,但這種情況下,系統(tǒng)一定能保留并恢復(fù)被覆蓋的區(qū)域,所以此時(shí)并不會(huì)發(fā)送WM_PAINT消息來要求應(yīng)用程序去刷新其顯示區(qū)。在Windows 應(yīng)用程序的窗口函數(shù)中,對(duì)WM_PAINT消息的處理就是刷新其用戶區(qū),這是一種固定的程序結(jié)構(gòu)。
為提高刷新效率,我們可以只刷新用戶區(qū)的一小部分,其余沒有發(fā)生變化的我們可以不予刷新,窗口函數(shù)可以通過調(diào)用函數(shù)InvalidateRect顯式地使用戶區(qū)內(nèi)的一個(gè)矩形無效。而且只有當(dāng)窗口客戶區(qū)的某一部分失效時(shí),其窗口函數(shù)才會(huì)收到WM_PAINT消息。
刷屏閃爍的產(chǎn)生原因與解決方法
當(dāng)客戶區(qū)有所改動(dòng),而又要將改動(dòng)顯示出來,就必然要強(qiáng)制Windows發(fā)送一條WM_PAINT消息,從而引發(fā)OnDraw函數(shù)的重畫,這樣雖完成了圖形的顯示,卻也會(huì)引起較明顯的閃爍,當(dāng)畫面上數(shù)據(jù)不是很多時(shí)尚不明顯,當(dāng)客戶區(qū)有成千上萬個(gè)點(diǎn)的時(shí)候刷新一次會(huì)引起整幅畫面的劇烈跳動(dòng),尤其是對(duì)于許多實(shí)時(shí)監(jiān)控軟件和矢量電子地圖軟件,此類軟件通常在屏幕上都會(huì)動(dòng)輒幾千、幾萬個(gè)要素點(diǎn),很明顯單靠發(fā)送WM_PAINT 消息引發(fā)OnDraw 的重畫根本滿足不了實(shí)際需求。
為了解決上述問題,我們需要做一些相應(yīng)的處理。首先要先檢取無效區(qū),然后創(chuàng)建一個(gè)與原設(shè)備環(huán)境句柄pDC相兼容的內(nèi)存設(shè)備環(huán)境,之后就可以采用在內(nèi)存中繪制圖形并把繪好的圖形以位圖方式從內(nèi)存拷貝到窗口客戶的方法來消除刷屏?xí)r引起的閃爍。這還需要?jiǎng)?chuàng)建一個(gè)與原設(shè)備環(huán)境句柄pDC相兼容的、大小為整個(gè)客戶區(qū)的位圖。然后再使新的設(shè)備環(huán)境dc與pDC具有同樣的映射關(guān)系,將位圖選入內(nèi)存環(huán)境。再使dc的整個(gè)客戶區(qū)都成無效區(qū),再“與上”所檢取的無效區(qū),使內(nèi)存環(huán)境與pDC檢取的無效區(qū)相等。之后便可以進(jìn)行繪圖工作了,繪圖完畢之后應(yīng)當(dāng)釋放所獲取的設(shè)備環(huán)境句柄pDC。否則會(huì)造成系統(tǒng)資源的浪費(fèi)。
程序示例
本示例程序通過打開任意存檔文件,將其ASCII碼碼值當(dāng)作要顯示的數(shù)據(jù),并通過一圖畫控件將其數(shù)據(jù)以圖形的形式依次顯示出來。本程序要處理的數(shù)據(jù)量較大,如不采用本文所述方法將會(huì)有很明顯的閃爍。
首先新建一基于CFormView的單文檔應(yīng)用程序WaveShower并在Form上添加一"picture"控件,設(shè)置其ID為IDC_SCREEN、Type為Rectangle、Color為Black。在"Extended Styles"屬性頁里選中Modal Frame檢查框。繼續(xù)添加一菜單“打開數(shù)據(jù)文件”,并生成其響應(yīng)函數(shù)OnOpenData()。同時(shí)在視類中添加如下成員變量:
int m_BufLen; //數(shù)據(jù)長(zhǎng)度
unsigned char* buffer; //數(shù)據(jù)緩存
int m_dx; //數(shù)據(jù)偏移量
int m_DY; //數(shù)據(jù)顯示區(qū)的幅度
CPoint* value; //將要顯示的數(shù)值
int m_DX; //數(shù)據(jù)顯示區(qū)的寬度
int m_Y0; //數(shù)據(jù)顯示區(qū)參照點(diǎn)位置
CRect rect; //數(shù)據(jù)顯示區(qū)矩形
然后在視類中添加函數(shù)GetScreenRect()用以獲取數(shù)據(jù)顯示區(qū)的大小及其他參數(shù);添加函數(shù)CleanScreen()完成清除數(shù)據(jù)顯示區(qū)的功能;添加函數(shù)DrawPoint()以便在數(shù)據(jù)顯示區(qū)畫點(diǎn):
void CWaveShowerView::GetScreenRect()
{
CWnd* pStatic = GetDlgItem(IDC_SCREEN);
pStatic->GetWindowRect(&rect);
ScreenToClient(&rect);
rect.top =4;
rect.left =4;
rect.bottom-=4;
rect.right-=4;
m_Y0=(rect.bottom-rect.top)/2 rect.top;
m_DX=rect.Width();
m_DY=rect.Height()/2;
value=new CPoint[m_DX];
}
void CWaveShowerView::CleanScreen()
{
CDC* pDC=GetDC();
CPen pen1(PS_SOLID,1,RGB(0,0,0));
CPen* oldPen1=pDC->SelectObject(&pen1);
for(int i=rect.top;i<rect.bottom;i )
{
pDC->MoveTo(rect.left,i);
pDC->LineTo(rect.right,i);
}
pDC->SelectObject(&oldPen1);
CPen pen2(PS_SOLID,1,RGB(0,0,255));
CPen* oldPen2=pDC->SelectObject(&pen2);
pDC->MoveTo(rect.left,m_Y0);
pDC->LineTo(rect.right,m_Y0);
pDC->SelectObject(&oldPen2);
ReleaseDC(pDC);
}
void CWaveShowerView::DrawPoint(CPoint pt, COLORREF color)
{
CDC* pDC=GetDC();
pDC->SetPixel(rect.left pt.x,m_Y0-pt.y,color);
ReleaseDC(pDC);
}
接下來,在視類的OnInitialUpdate()初始化函數(shù)中添加代碼以進(jìn)行數(shù)據(jù)顯示的各項(xiàng)前期準(zhǔn)備工作,并在“打開數(shù)據(jù)文件”菜單的響應(yīng)函數(shù)中添加代碼以讀取文件的內(nèi)碼。
void CWaveShowerView::OnInitialUpdate()
轉(zhuǎn)載請(qǐng)說明出處:六百號(hào)技術(shù) - SEO優(yōu)化,網(wǎng)頁設(shè)計(jì),網(wǎng)絡(luò)編程,軟件技巧,網(wǎng)絡(luò)知識(shí),系統(tǒng)技術(shù) ? VC 大數(shù)據(jù)量繪圖時(shí)無閃爍刷屏技術(shù)實(shí)現(xiàn)
標(biāo)簽: