windows程式設計讀書筆記之練習一
阿新 • • 發佈:2019-01-04
看完第5章,突然想寫一個類cad的程式,先做簡單功能描述及可能用到的函式
1、畫直線,線寬、線形可以設定,滑鼠左鍵開始繪圖,滑鼠移動時,跟蹤滑鼠繪製直線,再次左鍵,直線繪製完畢,同時開始繪製下一直線,右鍵結束直線繪製。線形線寬在開始繪圖時設定。
2、滑鼠滾動,放大 縮小, 放大的中心區為滑鼠位置。
問題1的解決過程,有意思的地方是,直線的末端跟隨滑鼠調整直線的位置。在這滑鼠移動的事件中,不停的繪製 起點 到 終點(當前滑鼠座標)的直線,
a、那麼問題來了,滑鼠前一位置畫出的直線怎麼辦? 解決之道, 要麼處理當前 WM_MOUSEMOVE 訊息時, 用背景色繪製 前面一條直線(相當於把前面那條直線擦除),再繪製當前直線。
b、問題又來了,如果前一條直線與已繪製的直線有交點時, 那麼擦除前一條直線時,同時把已繪製的直線上的那個交點也擦除了。這種狀態在windows繪圖軟體中也是存在的。後畫上的直線會把前面的直線覆蓋掉。
如果要解決上面的問題,目前能想到的解決方案是,把圖形的繪製丟給WM_PAINT,它的每次更新都是當前影象的最新狀態。 但是問題又來了,隨著圖元的增加,WM_PAINT會越來越慢。
在對問題2的探索過程中,發現如果真的要實現類cad功能的話,得放棄GDI了 轉向向量圖尋找解決方案。
1、記錄當前滑鼠點座標,
2、放大後點座標 = 相對座標X放大係數 + 滑鼠當前座標。
注意:
滾輪的滾動使Windows產生的WM_MOUSEWHEEL訊息,引數lParam包含滑鼠的位置資訊,但是,這些座標是相對於螢幕左上角的座標,而不是客戶區的座標。
所以,程式裡使用的座標是有WM_MOUSEMOVE訊息中得到的。
#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 ("DrawLines") ; 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 ("Connect-the-Points Mouse Demo"), 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]; line lineTmp; HDC hdc ; PAINTSTRUCT ps ; static POINT aptStart = {0,0}, aptEnd = { 0,0 }, aptCurrent; static BOOL fdraw = 0; switch (message) { case WM_CREATE: hPen[0] = CreatePen(PS_SOLID, 2, RGB(0, 0, 0)); hPen[1] = CreatePen(PS_SOLID, 1, RGB(0, 0, 0)); hPen[2] = CreatePen(PS_DASH, 1, RGB(0, 0, 0)); return 0; case WM_SIZE: cxClient = LOWORD(lParam); cyClient = HIWORD(lParam); 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++; } aptStart = aptEnd; fdraw = 1; InvalidateRect(hwnd, NULL, TRUE); 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); InvalidateRect(hwnd,NULL,TRUE); } 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); } return 0; case WM_PAINT: hdc = BeginPaint (hwnd, &ps) ; SetCursor (LoadCursor (NULL, IDC_WAIT)) ; ShowCursor (TRUE) ; if (iCount == 0 && fdraw) { SetPixel(hdc, aptStart.x, aptStart.y, 0); MoveToEx(hdc, aptStart.x, aptStart.y, NULL); LineTo(hdc, aptEnd.x, aptEnd.y); } else if (iCount != 0 && !fdraw) { for (int i = 0; i < iCount; i++) { MoveToEx(hdc, lines[i].ptStart.x, lines[i].ptStart.y, NULL); LineTo(hdc, lines[i].ptEnd.x, lines[i].ptEnd.y); } } else if (iCount != 0 && fdraw) { for (int i = 0; i < iCount; i++) { MoveToEx(hdc, lines[i].ptStart.x, lines[i].ptStart.y, NULL); LineTo(hdc, lines[i].ptEnd.x, lines[i].ptEnd.y); } MoveToEx(hdc, aptStart.x, aptStart.y, NULL); LineTo(hdc, aptEnd.x, aptEnd.y); } ShowCursor (FALSE) ; SetCursor (LoadCursor (NULL, IDC_ARROW)) ; EndPaint (hwnd, &ps) ; if (!lines_scaled.empty()) lines_scaled.clear(); lines_scaled = lines; return 0 ; case WM_DESTROY: PostQuitMessage (0) ; DeleteObject(hPen[0]); DeleteObject(hPen[1]); DeleteObject(hPen[2]); return 0 ; } return DefWindowProc (hwnd, message, wParam, lParam) ; }