程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> 關於VC++ >> 類似畫筆的繪圖控件

類似畫筆的繪圖控件

編輯:關於VC++

源代碼運行效果圖如下:

想必大家都用過WINDOWS自帶的畫筆,這是一個小巧易用的軟件。在業余時間,我模擬畫筆自己開發了一個類似的程序(當然不如畫筆那麼功能豐富)。它主要完成的功能有畫直線、曲線、圓、橢圓、矩形、多邊形;支持剪貼板的操作;支持撤銷、重復;保存成位圖文件;打開位圖文件。這個例子是用MFC開發的,為了方便使用,最後將轉換成控件。

建立單文檔工程Demo,下面將分四部分介紹相關功能的實現。 

一、 繪圖功能

本程序包含多種圖元:直線、曲線、圓、橢圓、矩形等,使用不同的圖元類實現,這些圖元類均派生於同一個基類:CDrawObject。這樣可以大大簡化不同圖元的處理過程。

雖然不同的圖元具有不同的表現形式和數據結構,但它們具有許多相同的特性,如都具有顏色定義功能,都有圖元繪制函數等,在基類中對這些共有的數據成員和成員函數進行描述。圖元基類的定義如下:

class CDrawObject : public CObject
{
private:
  COLORREF m_PenColor;//圖元顏色
  int  m_iPenWidth; //畫筆寬度
  bool m_bFill;   //是否填充
public:
  bool m_bSelected;
  long m_nStyle;//圖元類型
  CDrawObject(){m_bSelected = false;};
  void SetPenColor(COLORREF color);//設置圖元顏色
  COLORREF GetPenColor();//獲得圖元顏色
  void SetPenWidth(int width) {m_iPenWidth = width;};
  int GetPenWidth() {return m_iPenWidth;};
  void SetFill(bool fill) { m_bFill = fill;};
  bool GetFill() {return m_bFill;};
  virtual void Draw(CDC* pDC) {};
  virtual void MoveAt(CDC* pDC, long x, long y) {};
  virtual  void EndPoint(CDC* pDC) {};
  virtual void NewPoint(long x, long y){};
  //圖形對象第一點坐標,如果返回false則結束繪圖
  virtual int AddPoint(long x, long y){return 0;};
};

各圖元的具體實現函數請參考源代碼。

繪圖功能的實現主要是在視類中完成的。首先建立相應的菜單和工具欄按鈕用來設置圖元的樣式、顏色、畫筆的粗細、是否填充等等。還要重載OnLButtonDown(按下鼠標左鍵)、OnMouseMove(鼠標移動)、OnLButtonUp(松開鼠標左鍵)三個函數。創建過程如下:

1、 按下左鍵,創建新的圖元類實例;

2、 跟蹤鼠標移動修改圖元,獲得所見即所得的視覺效果;

3、 松開左鍵,繪制結束。 

二、 剪貼板操作

和剪貼板操作相關的函數主要有以下幾個:

打開剪貼板:OpenClipboard();

清空剪貼板:EmptyClipboard();

保存至剪貼板:SetClipboardData (CF_BITMAP, bitmap.GetSafeHandle() );

取出剪貼板的內容:GetClipboardData(CF_BITMAP);

關閉剪貼板:CloseClipboard();

至於視覺效果的實現,本來應該用"橡皮筋類",這裡偷了點兒懶,直接畫了矩形:)。剪切和拷貝的實現方法基本相同,剪切時需要清空選中的矩形區域。粘貼時需要先判斷剪切板中有無內容。 

三、 撤銷和重復

為了實現撤銷和重復,我自己定義了一個類Stack,該類的主要功能類似於一個棧,可以在初始化時定義棧的大小,可以彈出棧頂元素、增加新元素等等,除此以外還保存了一個表示當前位置的指針m_iCurPos。撤銷時該指針向前移動,重復時向後移動,如果撤銷後又有了新操作,則當前長度應改至m_iCurPos,即棧中m_iCurPos之後的元素無效。 至於棧中保存的內容,則是在每次操作後調用自己定義的SaveInStack()函數,將屏幕內容保存到一個HBITMAP類型的變量中。(這個方法有點兒笨,不過我實在想不出更好的方法了:(。但這個方法的實際效果還是不錯的。)

四、 打開和保存

有了前面的基礎,著部分比較容易實現。

打開文件的主要函數是:

HBITMAP hbmp = (HBITMAP)LoadImage(NULL, _T(path), IMAGE_BITMAP,
  0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE);
pDC->BitBlt(0, 0, bm.bmWidth, bm.bmHeight, &dc, 0, 0, SRCCOPY);

具體實現過程請參考源代碼。

以上是MFC程序的實現過程,接下來我們把它轉化成控件。

五、轉化成控件

1、新建控件

啟動Microsoft Visual C++ 6.0,單擊File下拉菜單下的New命令,在Profects標簽下選擇MFC ActiveX ControlWizard。輸入工程名WinPainter;

2、引入ActivDoc.h和ActivDoc.cpp文件;

3、在CwinPainterCtrl類的構造函數中添加

AddDocTemplate(new CActiveXDocTemplate(
   RUNTIME_CLASS(CDemo1Doc),
   RUNTIME_CLASS(CMainFrame),
   RUNTIME_CLASS(CDemo1View)));

4、 將剛才開發的MFC工程中的視類、文檔類、框架類的頭文件、實現文件,還有圖元類以及Stack類的文件統統包含進來,這時各類的消息函數可以正常響應,但菜單、工具欄等資源需要重新定義;

5、 在CWinPainterCtrl類中調用視類的函數,舉例:

CDemo1View* m_pView;
m_pView = (CDemo1View *)(GetFrameWnd()->GetActiveView());
ASSERT(m_pView);
m_pView->OnEditCopy();

調用MFC中其它類的函數與此類似。

6、 增加控件的屬性和方法。

至此,控件開發完畢。

控件運行測試效果圖如下:

參考文獻: 王宏 李玉東 李罡 《Visual C++ 實戰演練》 人民郵電出版社

  1. 上一頁:
  2. 下一頁:
欄目導航
Copyright © 程式師世界 All Rights Reserved