最近做了一個類似Windows畫圖板的小程序,拿來和大家分享一下。功能和界面全部模仿於Windows自帶的畫圖板,界面如截圖。功能主要有: 手繪線、簡單圖形、文字輸入、圖塊拖放、重復撤銷、畫面縮放、打開保存圖片文件,另外為了直接從數據庫或者XML中存取圖片,另外還提供了從Base64編碼存取圖片的接口,其他還實現了和畫圖板同樣效果的工具箱及顏料盒。
1、繪圖:
繪制功能主要在OnLButtonDown、OnMouseMove、OnLButtonUp中實現,根據當前選擇的工具和工具的樣式進行繪制。程序中每種工具的繪制都是通過一個圖元對象實現,比如鋼筆、畫刷因為本質上都是手繪線所以都通過CDrawPen來實現、直線和矩形等都通過CDrawShape來實現,所有的圖元對象都放在文件DrawObject.h中,具體的實現請參見代碼。 另外為了避免屏幕的閃爍,程序中做了兩個處理:一、把視圖自己的重繪背景代碼屏蔽掉,即響應視圖的WM_ERASEBKGND消息,直接返回TRUE,並在Ondraw中程序自己繪制背景就可以了;二,在Ondraw中繪制的時候,先繪制到內存DC中,然後再貼回視圖的DC。這樣就基本上就可以避免屏幕的閃爍了。
2、撤銷重做:
由於整個程序較為簡單,就沒有采用把動作記錄下來的方式,只是采取了一個較簡單的方法,在每當一個圖元繪制動作結束時就把畫布的內容存到bmp中以備撤銷,這些歷史畫面存放在一個bmp數組中,並定義了一個Stack類來管理該數組(此實現方式參考了在線雜志21期《類似畫筆的繪圖控件-衛琳》,在此表示感謝!),然後在屏幕上繪制的時候就是把當前位圖貼到屏幕上,並把還沒存取位圖的圖元繪上就行了。
3、縮放:
一般視圖縮放的實現是通過DC的兩個函數來實現:SetViewportExt和SetWindowExt,但是這兩個函數只在MM_ISOTROPIC和MM_ANISOTROPIC這兩種映射模式下有效果,而常用的帶滾動條的視圖類CScrollView卻不支持這兩種模式(參見CScrollView::SetScrollSizes)的實現。所以只好把MFC的CScrollView的代碼拿過來改了一下以支持MM_ISOTROPIC映射模式,如下所示,具體參見程序文件“ADMMScrollView.h”:
::SetMapMode(hdc,MM_ISOTROPIC);
int XLogMm = ::GetDeviceCaps(hdc, HORZSIZE);
int YLogMm = ::GetDeviceCaps(hdc, VERTSIZE);
int XLogPix = ::GetDeviceCaps(hdc, HORZRES);
int YLogPix = ::GetDeviceCaps(hdc, VERTRES);
::SetWindowExtEx(hdc,XLogMm*100,YLogMm*100,NULL);
::SetViewportExtEx(hdc,(int)(XLogPix*fZoomScale),(int)(YLogPix*fZoomScale),NULL);
4、工具箱:
首先為了實現工具箱的按鈕分兩列顯示的效果,需要設置一下按鈕的TBBS_WRAPPED,參見程序中的CToolPaletteBar類;然後,選擇不同工具時展現出工具的樣式,比如選擇“直線”時列出可用的直線寬度樣式,該功能通過在ToolBar上放一個CListCtrl實現,當前的工具樣式通過圖標的方式展現,效果和畫圖板的類似。
5、顏料盒:
從CDialogBar類繼承了一個類,然後在WM_PAINT響應函數裡面繪制一個個小顏色矩形,並重寫其OnLButtonDown、OnRButtonDown、OnLButtonDblClk來和用戶交互,實現出來的效果還不錯,看上去和畫圖板的顏料盒一樣。
6、鼠標光標樣式:
首先在資源文件中增加需要的光標資源,然後在視圖的OnSetCursor消息函數中調用SetCursor函數來設置光標樣式就可以了,注意要判斷HitTest參數是否為HTCLIENT,不然的話鼠標移到了滾動條上的時候光標還是畫筆的樣式就讓人覺得怪怪的了。
最後總結一下,和Windows的畫圖板相比,這個小程序除了具有畫圖板基本上所有的功能外,還有這樣一些優點: 方便的文字輸入功能並且可以設置字體和文本的顏色、多步的撤銷重做功能、從BASE64編碼存取圖片。希望對需要的朋友有所幫助。
本文配套源碼