//========================================================================
//TITLE:
// EVC繪製位元影像--BeginPaint()與GetDC()的區別
//AUTHOR:
// norains
//DATE:
// Tuesday 29-August-2006
//========================================================================
1.BeginPaint()和GetDC()
在EVC中繪製位元影像比較方便,有不少現成的函數可供調用,我們所要注意的只是BeginPaint()或GetDC()的使用即可.
因為代碼比較簡單,所以不做更多解釋.
這是訊息迴圈函數:
LRESULT CALLBACK MainWndProc(HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM lParam)
{
......
switch(wMsg)
{
case WM_PAINT:
OnPaintMainWnd(hWnd,wMsg,wParam,lParam);
break;
......
}
return DefWindowProc(hWnd,wMsg,wParam,lParam);
......
}
響應WM_PAINT訊息的函數,在這裡進行位元影像的繪製:
LRESULT OnPaintMainWnd(HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd,&ps);
//Create a DC that matches the device
HDC hdcMem = CreateCompatibleDC(hdc);
//Load the bitmap
HANDLE hBmp= LoadImage(g_hInst_MainWnd,MAKEINTRESOURCE(IDB_MAINWND),IMAGE_BITMAP,0,0,0);
//Select the bitmap into to the compatible device context
HGDIOBJ hOldSel = SelectObject(hdcMem,hBmp);
//Get the bitmap dimensions from the bitmap
BITMAP bmp;
GetObject(hBmp,sizeof(BITMAP),&bmp);
//Get the window area
RECT rc;
GetClientRect(hWnd,&rc);
//Copy the bitmap image from the memory DC to the screen DC
BitBlt(hdc,rc.left,rc.top,bmp.bmWidth,bmp.bmHeight,hdcMem,0,0,SRCCOPY);
//Restore original bitmap selection and destroy the memory DC
SelectObject(hdcMem,hOldSel);
DeleteDC(hdcMem);
EndPaint(hWnd,&ps);
return 0;
}
我們都知道BeginPaint()和EndPaint()需要配套使用,並且這兩個函數也只能用在WM_PAINT訊息的相應函數當中.如果我們在WM_PAINT的響應函數中將以上兩個繪製函數相應替換為GetDC()和ReleaseDC()會有什麼結果呢?
即:
HDC hdc = BeginPaint(hWnd,&ps); --> HDC hdc = GetDC(hWnd);
EndPaint(hWnd,&ps); --> ReleaseDC(hWnd,hdc);
編譯並運行程式,我們發現視窗一片空白,好像沒有繪製位元影像.但其實不盡然,我們採用單步調試,可以發現其實位元影像已經繪製出來,只不過又被背景顏色抹掉了.由此可知,如果需要使用GetDC(),我們對訊息迴圈函數必須要加上對WM_ERASEBKGND的處理:
LRESULT CALLBACK MainWndProc(HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM lParam)
{
switch(wMsg)
{
case WM_PAINT:
OnPaintMainWnd(hWnd,wMsg,wParam,lParam);
break;
case WM_ERASEBKGND
return 0;
}
return DefWindowProc(hWnd,wMsg,wParam,lParam);
}
只要系統不對WM_ERASEBKGND進行預設處理,我們用GetDC()替代BeginPaint()就可以正常使用.
至此我們可以看出BeginPaint(),EndPaint()和GetDC(),ReleaseDC()的區別.前一對只能用在WM_PAINT響應函數中,並且繪製背景時不會被抹掉;後一對隨處可用,但如果用在WM_PAINT響應函數中,那麼接下來將會被WM_ERASEBKGND訊息的響應函數的背景繪製給抹掉.
2.繪圖閃爍問題
有時候我們大量繪製螢幕時,可能會出現螢幕閃爍問題,這時候可以採用雙緩衝的做法.步驟首先是建立一個記憶體DC,然後往記憶體DC中繪圖,最後把記憶體DC的內容複寫到顯示DC中,完成繪製.具體過程並不複雜,結合代碼來說明一下.
PS:這段代碼也是相應WM_PAINT 訊息的.
PAINTSTRUCT ps;
HDC hdc;
//擷取螢幕顯示DC
hdc = BeginPaint (hWnd, &ps);
//建立記憶體DC
HDC hdcMem = CreateCompatibleDC(hdc);
//建立一個bmp記憶體空間
HBITMAP hBmp = CreateCompatibleBitmap(hdc,SCREEN_WIDTH,SCREEN_HEIGHT);
//將bmp記憶體空間分配給記憶體DC
HGDIOBJ hOldSel = SelectObject(hdcMem,hBmp);
//這是使用者需要繪製的畫面,全部往記憶體DC繪製
Rectangle(hdcMem,0,0,SCREEN_WIDTH,SCREEN_HEIGHT);
DrawMenuButton(hdcMem);
//將記憶體DC的內容複寫到螢幕顯示DC中,完成顯示
BitBlt(hdc,0,0,SCREEN_WIDTH,SCREEN_HEIGHT,hdcMem,0,0,SRCCOPY);
//清除資源
SelectObject(hdcMem,hOldSel);
DeleteDC(hdcMem);
EndPaint(hWnd,&ps);