//========================================================================
//TITLE:
// 輕松消除貼圖閃爍
//AUTHOR:
// norains
//DATE:
// Thursday 25-December -2006
//Environment:
// EVC4.0 + Standard SDK
//========================================================================
有沒有在程序中嘗試過貼圖?我們都有這么一個(gè)經(jīng)驗(yàn),如果直接往屏幕貼圖,一張圖我們覺得顯示正常流暢;兩張圖,如果圖片不大,并且速度也夠快的話,我們也覺得沒問題;但如果,有一張很大的位圖,并且我們需要在位圖上面輸出文本,甚至在這張位圖上面還要再貼另外的位圖----可能是兩張,也可能是十張,甚至是百張----那展現(xiàn)在我們面前的將是什么呢?我們將看到,屏幕上位圖緩慢地一張一張出現(xiàn),造成一種讓人煩躁的閃爍效果.
那有沒有辦法實(shí)現(xiàn)上面所需的功能,并且又不顯得閃爍呢?方法當(dāng)然有,并且也極為簡單.一句話,就是把所有的數(shù)據(jù)往內(nèi)存里寫,然后再把內(nèi)存的數(shù)據(jù)顯示到屏幕上.
好了,那現(xiàn)在讓我們開始吧!
首先,讓我們獲取一個(gè)屏幕的DC.這個(gè)DC嘛,就是顯示給我們看的屏幕的設(shè)備.
HDC hdc = GetDC(m_hWnd);
如果代碼是用來響應(yīng)WM_PAINT,那么這個(gè)DC句柄的獲得應(yīng)該使用另外一個(gè)函數(shù):
HDC hdc = BeginPaint(m_hWnd,&ps);
嗯,接下來我們要做的就是,創(chuàng)建一個(gè)和設(shè)備DC相符合的內(nèi)存DC.換句話說,就是開辟一塊內(nèi)存空間,并且這空間的大小足以用來表示設(shè)備DC的數(shù)據(jù).
HDC hdcMem = CreateCompatibleDC(hdc);
內(nèi)存分配完畢之后,我們需要告訴程序這內(nèi)存是用來干什么的,也就是說,這內(nèi)存的格式是什么.這和變量聲明比較像,不過卻更為復(fù)雜.
最初,我們需要?jiǎng)?chuàng)建一個(gè)符合目前設(shè)備DC的位圖格式:
HBITMAP hBitmap = CreateCompatibleBitmap(hdc,IMG_MAINWND_WIDTH,IMG_MAINWND_HEIGHT);
最后就是把創(chuàng)建的這個(gè)位圖和內(nèi)存DC關(guān)聯(lián).
HGDIOBJ hOldSel = SelectObject(hdcMem,hBitmap);
好了,供貼圖的內(nèi)存已經(jīng)準(zhǔn)備好了,現(xiàn)在我們想干嘛就可以干嘛了.嗯,那我們還是趕快嘗試一把吧.好,就先從位圖繪制開始吧.
由于位圖的繪制比較復(fù)雜,并且其數(shù)據(jù)必須要和內(nèi)存關(guān)聯(lián),然后才能讀取位圖的數(shù)據(jù).所以我們第一步還是需要先建立一個(gè)適合設(shè)備DC的位圖DC:
HDC hdcBmp = CreateCompatibleDC(hdc);
讀取位圖數(shù)據(jù):
HANDLE hBmp= LoadImage(m_hInst,MAKEINTRESOURCE(IDB_MAINWND),IMAGE_BITMAP,0,0,0);
將位圖數(shù)據(jù)和位圖DC關(guān)聯(lián)起來:
HGDIOBJ hOldBmpSel = SelectObject(hdcBmp,hBmp);
將位圖數(shù)據(jù)復(fù)制到內(nèi)存DC中:
BitBlt(hdcMem,0,0,IMG_MAINWND_WIDTH,IMG_MAINWND_HEIGHT,hdcBmp,0,0,SRCCOPY);
好了,現(xiàn)在位圖已經(jīng)繪制到內(nèi)存去了,看起來也不是很復(fù)雜嘛!
如果我們想在內(nèi)存中輸出文本,該怎么做呢?呵呵,這比繪制位圖要簡單多了:
DrawText(hdcMem,TEXT("輸出文本"),-1,&rc,DT_LEFT);
嗯,就是這樣,僅僅一條語句.如果還想讓輸出的文本背景透明,并且也想改變字體的顏色,在繪圖前我們之需要添加以下語句即可:
COLORREF oldColor;
SetBkMode(hdcMem,TRANSPARENT);
oldColor = SetTextColor(hdcMem,RGB(40,96,170));
當(dāng)然,繪制完畢之后,把原來的顏色還原是一個(gè)好習(xí)慣:
SetTextColor(hdcMem,oldColor);
做到現(xiàn)在,是不是已經(jīng)迫不及待地想將成果顯示到屏幕上了呢?好,那就讓我們看看成果吧:
BitBlt(hdc,rc.left,rc.top,(rc.right - rc.left),(rc.bottom - rc.top),hdcMem,rc.left,rc.top,SRCCOPY);
怎么樣?是不是顯示得非常流暢,完全沒有閃爍的現(xiàn)象?
做到這里,是不是非常高興,就想著拿這段代碼去應(yīng)用了?等等,先別急,我們還需要清除一下我們狂歡后留下的垃圾,否則,系統(tǒng)這家伙就要生氣,說不定就會來個(gè)藍(lán)屏當(dāng)機(jī)哦!
SelectObject(hdcBmp,hOldBmpSel);
SelectObject(hdcMem,hOldSel);
DeleteObject(hBitmap);
DeleteDC(hdcMem);
ReleaseDC(m_hWnd,hdc); //如果是響應(yīng)WM_PAINT消息,這里應(yīng)改成:EndPaint(m_hWnd,&ps);
如果我們想做得更完美一些,甚至可以不用響應(yīng)WM_ERASEBKGND消息.因?yàn)閃M_ERASEBKGND會占用一幀來繪制.所以我們需要做的是,只要檢測到WM_ERASEBKGND消息,直接返回.
附錄1.
無閃爍的完整代碼(其中的一些未知變量,窗口句柄需根據(jù)實(shí)際情況更改):
HDC hdc = GetDC(m_hWnd);
//Create a DC that matches the device
HBITMAP hBitmap = CreateCompatibleBitmap(hdc,IMG_MAINWND_WIDTH,IMG_MAINWND_HEIGHT);
HDC hdcMem = CreateCompatibleDC(hdc);
//Select the bitmap into to the compatible device context
HGDIOBJ hOldSel = SelectObject(hdcMem,hBitmap);
//Create a DC that matches the device
HDC hdcBmp = CreateCompatibleDC(hdc);
//Load the bitmap
HANDLE hBmp= LoadImage(m_hInst,MAKEINTRESOURCE(IDB_MAINWND),IMAGE_BITMAP,0,0,0);
//Select the bitmap into to the compatible device context
HGDIOBJ hOldBmpSel = SelectObject(hdcBmp,hBmp);
//Copy the bitmap image to the memory DC
BitBlt(hdcMem,0,0,IMG_MAINWND_WIDTH,IMG_MAINWND_HEIGHT,hdcBmp,0,0,SRCCOPY);
COLORREF oldColor;
SetBkMode(hdcMem,TRANSPARENT);
oldColor = SetTextColor(hdcMem,RGB(40,96,170));
DrawText(hdcMem,lpcszText,-1,&m_rcInfoArea,DT_LEFT);
SetTextColor(hdcMem,oldColor);
BitBlt(hdc,m_rcInfoArea.left,m_rcInfoArea.top,(m_rcInfoArea.right - m_rcInfoArea.left),(m_rcInfoArea.bottom - m_rcInfoArea.top),hdcMem,m_rcInfoArea.left,m_rcInfoArea.top,SRCCOPY);
//Restore original bitmap selection and destroy the memory DC
SelectObject(hdcBmp,hOldBmpSel);
SelectObject(hdcMem,hOldSel);
DeleteObject(hBitmap);
DeleteDC(hdcMem);
ReleaseDC(m_hWnd,hdc);
附錄2
會閃爍的代碼
InvalidateRect(m_hWnd,&m_rcInfoArea,TRUE);
HDC hdc = GetDC(m_hWnd);
//Create a DC that matches the device
HDC hdcBmp = CreateCompatibleDC(hdc);
//Load the bitmap
HANDLE hBmp= LoadImage(m_hInst,MAKEINTRESOURCE(IDB_MAINWND),IMAGE_BITMAP,0,0,0);
//Select the bitmap into to the compatible device context
HGDIOBJ hOldSel = SelectObject(hdcBmp,hBmp);
//Get the bitmap dimensions from the bitmap
BITMAP bmp;
GetObject(hBmp,sizeof(BITMAP),&bmp);
//Copy the bitmap image from the memory DC to the screen DC
BitBlt(hdc,m_rcInfoArea.left,m_rcInfoArea.top,(m_rcInfoArea.right - m_rcInfoArea.left),(m_rcInfoArea.bottom - m_rcInfoArea.top),hdcBmp,m_rcInfoArea.left,m_rcInfoArea.top,SRCCOPY);
//Restore original bitmap selection and destroy the memory DC
SelectObject(hdcBmp,hOldSel);
COLORREF oldColor;
SetBkMode(hdc,TRANSPARENT);
oldColor = SetTextColor(hdc,RGB(40,96,170));
DrawText(hdc,lpcszText,-1,&m_rcInfoArea,DT_LEFT);
SetTextColor(hdc,oldColor);
DeleteDC(hdcBmp);
ReleaseDC(m_hWnd,hdc);