介紹
您好!這是我在CodeProject上的第四篇文章。遷移到VC++,我第一個關注的是通過VC++幫助能夠創建自定義控件,因為這是一個非常用有的特性,當你要修改任意控件的內容或創建新的控件的時候。所以我決定寫這篇文章,這樣新的開發者或第一次開發控件的人就能夠從中得到幫助。
這就是所有的介紹,現在轉到最初的觀點:怎么創建自定義控件,為什么要創建自定義控件。我對在Win32 API下開發應用程序很感興趣,因為它小巧並能獨立運行,我從沒用VC++開發過,但它是非常強大的語言,並且它強大的特性已經吸引我轉向了它。自定義控件就是其中之一。CodeProjet上有很多使用自定義控件的文章。但是第一次閱讀它們的時候,我不明白在簡單的Windows應用程序中怎樣去創建、獲取和處理消息。自定義控件給開發者帶來了一種方便的方式去創建控件並使其和其它常規控件一樣可視化。(因為我是VC++的初學者,所以文章中如果有錯請告知我)。
它在哪里
現在的問題是,自定義控件在哪里?答案就在下面。下圖顯示了自定義控件,它躺在控件欄中。

這個圖顯示了這個自定義控件的位置。你可以選擇它,並能在你的窗體資源中直接繪制。這里最主要的問題是當你把這個控件放到你的窗體在,然后你編譯並執行程序,你會看不到效果,因為你還沒有為這個控件選擇一個類,所以這個問題在后面的章節討論。
創建一個類
現在,下圖顯示了自定義控件在窗體中繪制。現在,你在自定義控件上面右擊並在彈出的菜單上選擇“類向導”(ClassWizard)。

選擇一個類
在你點擊“類向導”之后,下面這個對話框就會在屏幕上顯示。在它上面,選擇“添加類”(Add Class)然后選“New...”

現在,當你點擊New按鈕后,給自定義控件選擇基類的對話框就會出現如下面所示。在此,對於基類你有多個選擇。意思就是你可以自定義基礎控件,比如給靜態控件或者編輯控件添加新特性,或者你可以創建一個全新的控件。我決定創建一個全新的控件,像便箋本那樣,所以,我選擇基礎類CWnd作為基類。

最后,你已經給你的控件創建了類。現在,重要部分開始了……
因為之前創建的類使用CWnd作為基類,我們要注冊這個類因為這是一個自定義的類。所以,我們必須寫函數RegisterWndClass去注冊它。函數的代碼可能像下面這樣……
BOOL MyCustomControl::RegisterWndClass() { WNDCLASS windowclass; HINSTANCE hInst = AfxGetInstanceHandle(); //Check weather the class is registerd already if (!(::GetClassInfo(hInst, MYWNDCLASS, &windowclass))) { //If not then we have to register the new class windowclass.style = CS_DBLCLKS;// | CS_HREDRAW | CS_VREDRAW; windowclass.lpfnWndProc = ::DefWindowProc; windowclass.cbClsExtra = windowclass.cbWndExtra = 0; windowclass.hInstance = hInst; windowclass.hIcon = NULL; windowclass.hCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW); windowclass.hbrBackground = ::GetSysColorBrush(COLOR_WINDOW); windowclass.lpszMenuName = NULL; windowclass.lpszClassName = MYWNDCLASS; if (!AfxRegisterClass(&windowclass)) { AfxThrowResourceException(); return FALSE; } } return TRUE; }
用這種方式,我們已經注冊了這個新的窗口類。現在,你要像下面這樣添加這個函數到類的默認構造函數中:
MyCustomControl::MyCustomControl() { //Register My window class RegisterWndClass(); }
我想有人會想MYWNDCLASS是個什么。答案是它是我們自定義控件的類名。它定義在MyCustomControl.h文件的的頂部,就像下面這樣:
#define MYWNDCLASS "MyDrawPad"
現在,我們就有了自己的類,名叫MyDrawPad。
附加類到自定義控件
所有這些做好之后,自定義控件我們就要創建完成了。最后剩下的事情是把自定義控件設置為我們創建好的窗口類。為此,在資源視圖里右擊自定義控件然后選擇它的屬性。一個對話像下面的對話框將會出現……

然后,設置類名為我們之前創建的MyDrawPad。這里你可以通過改變“Style”的編輯框16進制數的值來選擇窗口樣式。我已經試過了一些值,你們也可以試試。
實現數據交換
現在,所有的事情都做好了,但數據必須要在窗口和我們的應用程序之間進行交換。所以,在你的對話框類為我們的自定義控件添加變量,像下面這樣:
// Implementation protected: HICON m_hIcon; MyCustomControl m_drawpad;//This is our custom control
之后,你得添加在DoDataExchage()函數里添加下面的代碼,讓它與自定義控件進行交互。
void CCustomControlDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CCustomControlDlg) // NOTE: the ClassWizard will add DDX and DDV calls here DDX_Control(pDX,IDC_CUSTOM1,m_drawpad); //}}AFX_DATA_MAP }
現在,你做好准備動作了嗎???好,按Ctrl+F5編譯並執行程序。(但願你都做對了……我想沒有錯誤!!!)
別忘了在對話框的頭文件里寫#include "MyCustomControl.h",不然的話會生成很多錯誤。(我想你不會怪我哈哈哈)。
添加消息處理
上面的關鍵部分成功后,你就能看到對話框里有一個白色的矩形。這就是我們的自定義控件(相信我!)。這只是個不窗口。現在,我們添加一些窗口消息和我們的控件相交互。請仔細閱讀……
為了給窗口添加Windows消息,右擊MyCustomControl類並選擇Add Windows Message Handler來添加消息,如mouse move,click等等。

這樣子,在這么長(很長嗎?)的工作后,你已經創建了你的自定義控件。現在放松一下,開始由你們自己寫了。請對我的文章進行評論(我喜歡你們評論)。比如,我已經用包含的源代碼寫了一個簡單的DrawPad。
現在我們來梳理一下這篇文件的簡短概要:
要創建自定義控件,我們要做下面這些事情:
- 創建包含對話框的簡單的MFC應用程序。
- 從控件欄中選擇自定義控件。
- 在對話框資源里繪制自定義控件。
- 右擊自定義控件選擇類向導。
- 從Add Class菜單在添加新的類,選擇合適的基類。
- 添加代碼並注冊Custom Window class.
- 在對話框里給基類(自定義類)添加成員變量。
- 給已經注冊的窗口類設置自定義控件。
- 添加DoDataExchange代碼。
- 用Ctrl+F5編譯並執行程序。
- 在類視圖里通過右擊自定義控件類來添加/編輯Windows消息處理函數。
如果你喜歡它,給我郵件yogmj@hotmail.com,發送你的建議或文章里的拼寫錯誤。或者這些源代碼里的Bugs(因為
我是Bug獵手{我是這么認為的,你認為嗎?})
