MFC 定制控件(Customize Control) 及 MFC CWnd和WIN32 HWND關聯方法
<參考資料 MSDN MFC TNO 15>
文檔将概述MFC中定制自定義控件的3種方法:
擁有者繪制控件(Owner Drawing Control and Menu) 自繪制控件(self drawing control and menu) 和子集化(subclass)
1 使用MFC方法定制控件必備的幾個基本概念:
控制定制風格的控件的幾個标準Windows消息:
WM_MEASUREITEM
WM_COMPAREITEM
WM_DELETEITEM
WM_DRAWITEM
消息的詳細說明:
1.1 WM_MEASUREITEM
當自繪制風格(owner draw)的控件(owner-drawn button, combo box, list box, list view control, or menu item)建立時控件的父窗體将受到這個消息用于定制控件的大小
WM_MEASUREITE
MidCtl = (UINT) wParam;//控件的辨別
lpmis = (LPMEASUREITEMSTRUCT) lParam;//控件的大小資訊
消息處理的傳回值:
當函數處理了這個消息必須傳回TRUE
1.2 WM_COMPAREITEM
系統發送此消息用于設定一個需要排序的控件(如具有CBS_SORT風格的COMBOBOX,有LBS_SORT風格的LISTBOX)新插入項的位置資訊
idCtl = wParam; // 控件辨別
lpcis = (LPCOMPAREITEMSTRUCT) lParam; // 2個進行比較的子項資訊
消息處理的傳回值:
-1 子項1在子項2之前的位置
0 子項1,2 具有相等的排序位置
1 子項1在子項2之後的位置
1.3 WM_DELETEITEM
當ListBox或是combo box被銷毀時或它們的某一子項将被除去的時候(如消息 LB_DELETESTRING TCONTENT, CB_DELETESTRING CB_RESETCONTENT)系統會對應每一個被删除的控件子項發送消息給控件的父窗體
idCtl = wParam; //控件辨別
lpdis = (LPDELETEITEMSTRUCT) lParam; //删除子項資訊
消息傳回值
1.4 WM_DRAWITEM
當自繪制風格的button, combo box, list box, or menu 的視覺方式需要改變時将發送WM_DRAWITEM消息給所有者窗體
idCtl = (UINT) wParam; // 控件辨別
lpdis = (LPDRAWITEMSTRUCT) lParam; // 繪制控件的資訊
函數傳回值
2 以下内容為定制自定義控件的3種常見方法:
2.1 擁有者繪制控件或菜單(owner draw controls/menu)
windows支援擁有WS_OWNERDRAW風格的控件發送指定消息給控件的父窗體(控件或是菜單的擁有者)使得父窗體可以定制這些控件的視覺風格或行為
MFC在其消息路由中直接支援4種消息消息的處理:
CWnd::OnDrawItem
CWnd::OnMeasureItem
CWnd::OnCompareItem
CWnd::OnDeleteItem
可以在CWnd的派生類(通常是CMainFrame或是CDialog)中實作這些方法來定制控件
注意:
這種方法實作的又很大的弊端,代碼重用率低,這樣定制的控件如在另一個地方重用時隻能把代碼從一個地方拷貝到另一個地方
2.2 自繪制的控件或是菜單
MFC預設的實作owner draw标準消息的方法,将這些本來由父窗體實作的繪制的工作消息解碼發送到指定控件,由這些控件來處理這些消息,這種優雅的處理方式使得很容易實作重用率很高的自定義風格的控件
在這些封裝控件的MFC類(CMenu, CButton, CListBox, CListCtrl etc)中 ,隻需要派生一個新類并重寫對應的虛函數就可以輕松定制自定義風格的控件
如CMenu的DrawItem(), MesureItem()函數
2.3 動态子集化(dynamic subclassing)
2.3.1 subclass的概念:
子集化在windows程式設計中指用一個新的視窗過程(subclass winproc)取代舊的視窗過程,而是用舊的窗體過程(superclass winproc)作為預設的視窗處理,來使得窗體呈現新的特性;
superclass 和 subclass在windows程式設計中的概念可以用C++中的基類和派生類的關系來了解
在WIN32這個過程可以用API: SetWindowLong來實作
3.4.2 MFC CWnd和WIN32 HWND關聯的3種方法
方法一 建立一個CWnd時 CWnd對象建立一個HWND 此時的HWND的風格是可以更改的,如使用Create()
方法二 建立一個CWnd與一個已經存在的HWND關聯 此時HWND的風格是不可以被更改的 如使用Attach()
方法三 建立一個CWnd與一個已存在的HWND關聯,此時HWND的風格是可以更改的 這就是所謂的動态子集化(dynamic subclassing) 這樣就可以實作運作時态的改變一個窗體的行為
對于動态子集化MFC提供了兩個函數:
CWnd::SubclassWindow
CWnd::SubclassDlgItem.
使用動态子集化是控制界面風格最優雅的風格和方法,代碼重用率高和運作時态動态變化
一般一些比較優良的MFC第三方界面庫都是基于這種技術實作的