1. 程式人生 > >windows程式設計讀書筆記之練習一

windows程式設計讀書筆記之練習一

看完第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) ;
}