windows程式設計讀書筆記四
前面的程式碰到重新整理時碰到閃爍問題,百度一搜,一堆關於雙緩衝解決閃爍的文章。
具體實施方案為:
1、建立一個記憶體DC
hdcMem = CreateCompatibleDC(hdc);
此時,記憶體DC的顯示錶面是單色、1個畫素寬、1個畫素高。即顯示錶面僅僅1位。
2、CreateCompatibleBitmap建立一個與裝置相容的點陣圖,
::GetClientRect(hwnd, &rc);
hBitmap = CreateCompatibleBitmap(hdc, rc.right-rc.left, rc.bottom-rc.top);
3、把畫布物件選入記憶體DC
SelectObject(hdcMem, hBitmap);
4、將記憶體DC中的圖一次性丟給DC,或則將DC中的圖丟給記憶體DC
BitBlt(hdc, 0, 0, cxClient, cyClient, hdcMem, 0, 0, SRCCOPY);
BitBlt(hdcMem, 0, 0, cxClient, cyClient, hdc, 0, 0, SRCCOPY);
在用本方法改進前面的CAD程式碰到的問題
1、初始化時 ,將當前hdc內容丟給記憶體DC,BitBlt語句的位置。
a、放在WM_CREATE訊息中,裡面的內容是黑色的;
b、只有放置在WM_SIZE或WM_PAINT訊息內,內容才和DC一樣是白色(注意hdc的釋放及申請);
從上述兩點,可以看出,建立視窗時,windows系統並沒有繪製視窗。跟蹤發現,CreateWindow執行完畢,視窗並未繪製,而是在後面的ShowWindow時視窗完成了繪製,此刻後進入了WM_SIZE訊息,所以此時hdc內是有內容的,同理WM_PAINT發生在後面,hdc也是有內容。
2、剛開始改動時,延續了前面程式的做法,所有更新都在WM_PAINT中進行,無法避免閃爍。後面將繪製過程在響應訊息內完成,就好了。
/*-------------------------------------------------- 利用BitBlt來重新整理 --------------------------------------------------*/ #include <windows.h> #include <windowsx.h> #include <vector> using std::vector; vector<POINT> pt; enum LineStyle {HeavyLine, LightLine, DashLine}; struct line { POINT ptStart; POINT ptEnd; enum LineStyle lineStyel; }; vector<line> lines; vector<line> lines_scaled; LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ; int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static TCHAR szAppName[] = TEXT ("MyCAD") ; HWND hwnd ; MSG msg ; WNDCLASS wndclass ; wndclass.style = CS_HREDRAW | CS_VREDRAW ; wndclass.lpfnWndProc = WndProc ; wndclass.cbClsExtra = 0 ; wndclass.cbWndExtra = 0 ; wndclass.hInstance = hInstance ; wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ; wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ; wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ; wndclass.lpszMenuName = NULL ; wndclass.lpszClassName = szAppName ; if (!RegisterClass (&wndclass)) { MessageBox (NULL, TEXT ("Program requires Windows NT!"), szAppName, MB_ICONERROR) ; return 0 ; } hwnd = CreateWindow (szAppName, TEXT ("MyCAD"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL) ; ShowWindow (hwnd, iCmdShow) ; UpdateWindow (hwnd) ; while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg) ; DispatchMessage (&msg) ; } return msg.wParam ; } LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static int iCount =0; static int cxClient, cyClient; static float scaleratio = 1; static HPEN hPen[3]; static HBITMAP hBitmap, hBitmapTmp; static HDC hdcMem, hdcMemTmp; static RECT rc; static BOOL flagCreate; static BOOL flagClicked; line lineTmp; HDC hdc; PAINTSTRUCT ps ; static POINT aptStart = {0,0}, aptEnd = { 0,0 }, aptCurrent; static BOOL fdraw = 0; switch (message) { case WM_CREATE: flagCreate = TRUE; hdc = GetDC(hwnd); ::GetClientRect(hwnd, &rc); hdcMem = CreateCompatibleDC(hdc); hBitmap = CreateCompatibleBitmap(hdc, rc.right-rc.left, rc.bottom-rc.top); hdcMemTmp = CreateCompatibleDC(hdc); hBitmapTmp = CreateCompatibleBitmap(hdc, rc.right - rc.left, rc.bottom - rc.top); SelectObject(hdcMem, hBitmap); SelectObject(hdcMemTmp, hBitmapTmp); SelectObject(hdcMemTmp, hPen[1]); hPen[0] = CreatePen(PS_SOLID, 2, RGB(0, 0, 0)); hPen[1] = CreatePen(PS_SOLID, 1, RGB(0, 255, 0)); hPen[2] = CreatePen(PS_DASH, 1, RGB(0, 0, 0)); //此時hdc內沒有內容,將得到全黑影象 //BitBlt(hdcMem, 0, 0, rc.right - rc.left, rc.bottom - rc.top, hdc, 0, 0, SRCCOPY); //BitBlt(hdcMemTmp, 0, 0, rc.right - rc.left, rc.bottom - rc.top, hdc, 0, 0, SRCCOPY); ReleaseDC(hwnd, hdc); return 0; case WM_SIZE: cxClient = LOWORD(lParam); cyClient = HIWORD(lParam); //此時hdc內有內容,可以正常使用 //hdc = GetDC(hwnd); //BitBlt(hdcMem, 0, 0, rc.right - rc.left, rc.bottom - rc.top, hdc, 0, 0, SRCCOPY); //BitBlt(hdcMemTmp, 0, 0, rc.right - rc.left, rc.bottom - rc.top, hdc, 0, 0, SRCCOPY); //ReleaseDC(hwnd, hdc); return 0; case WM_LBUTTONDOWN: aptEnd.x = GET_X_LPARAM(lParam); aptEnd.y = GET_Y_LPARAM(lParam); if (fdraw != 0) { lineTmp.ptStart = aptStart; lineTmp.ptEnd = aptEnd; lineTmp.lineStyel = HeavyLine; lines.push_back(lineTmp); iCount++; } else { aptStart = aptEnd; SetPixel(hdcMem, aptStart.x, aptStart.y, 0); fdraw = 1; return 0; } MoveToEx(hdcMem, aptStart.x, aptStart.y, NULL); LineTo(hdcMem, aptEnd.x, aptEnd.y); hdc = GetDC(hwnd); BitBlt(hdc, 0, 0, cxClient, cyClient, hdcMemTmp, 0, 0, SRCCOPY); ReleaseDC(hwnd, hdc); aptStart = aptEnd; if (!lines_scaled.empty()) lines_scaled.clear(); lines_scaled = lines; return 0 ; case WM_RBUTTONDOWN: fdraw = 0; InvalidateRect(hwnd, NULL, TRUE); return 0; case WM_MOUSEMOVE: if (fdraw) { aptEnd.x = GET_X_LPARAM(lParam); aptEnd.y = GET_Y_LPARAM(lParam); BitBlt(hdcMemTmp, 0, 0, cxClient, cyClient, hdcMem, 0, 0, SRCCOPY); MoveToEx(hdcMemTmp, aptStart.x, aptStart.y, NULL); LineTo(hdcMemTmp, aptEnd.x, aptEnd.y); hdc = GetDC(hwnd); BitBlt(hdc, 0, 0, cxClient, cyClient, hdcMemTmp, 0, 0, SRCCOPY); ReleaseDC(hwnd, hdc); } aptCurrent.x= GET_X_LPARAM(lParam); aptCurrent.y = GET_Y_LPARAM(lParam); return 0 ; case WM_MOUSEWHEEL: if (!lines_scaled.empty()) { if ((short)HIWORD(wParam)>0) { scaleratio = 1.25; } else { scaleratio = 0.8; } for (int i = 0;i < (int)lines_scaled.size();i++) { lines_scaled[i].ptStart.x = scaleratio*(lines_scaled[i].ptStart.x - aptCurrent.x) + aptCurrent.x; lines_scaled[i].ptStart.y = scaleratio*(lines_scaled[i].ptStart.y - aptCurrent.y) + aptCurrent.y; lines_scaled[i].ptEnd.x = scaleratio*(lines_scaled[i].ptEnd.x - aptCurrent.x) + aptCurrent.x; lines_scaled[i].ptEnd.y = scaleratio*(lines_scaled[i].ptEnd.y - aptCurrent.y) + aptCurrent.y; } hdc = GetDC(hwnd); Rectangle(hdc,0,0, cxClient, cyClient); for (int i = 0; i < (int)lines_scaled.size(); i++) { MoveToEx(hdc, lines_scaled[i].ptStart.x, lines_scaled[i].ptStart.y, NULL); LineTo(hdc, lines_scaled[i].ptEnd.x, lines_scaled[i].ptEnd.y); } ReleaseDC(hwnd, hdc); } BitBlt(hdcMem, 0, 0, cxClient, cyClient, hdc, 0, 0, SRCCOPY); BitBlt(hdcMemTmp, 0, 0, cxClient, cyClient, hdc, 0, 0, SRCCOPY); return 0; case WM_PAINT: hdc = BeginPaint (hwnd, &ps) ; if (flagCreate) { BitBlt(hdcMem, 0, 0, rc.right - rc.left, rc.bottom - rc.top, hdc, 0, 0, SRCCOPY); BitBlt(hdcMemTmp, 0, 0, rc.right - rc.left, rc.bottom - rc.top, hdc, 0, 0, SRCCOPY); flagCreate = FALSE; return 0; } BitBlt(hdc, 0, 0, cxClient, cyClient, hdcMem, 0, 0, SRCCOPY); EndPaint (hwnd, &ps) ; return 0; case WM_DESTROY: PostQuitMessage (0) ; DeleteObject(hPen[0]); DeleteObject(hPen[1]); DeleteObject(hPen[2]); DeleteDC(hdcMem); DeleteObject(hBitmap); DeleteDC(hdcMemTmp); DeleteObject(hBitmapTmp); return 0 ; } return DefWindowProc (hwnd, message, wParam, lParam) ; }