TN014: 自訂控制項
此附註描述的 MFC 支援自訂和自繪控制項。 它也將告訴您動態的子類別化,並描述之間的關係 CWnd 物件,並HWNDs。
MFC 範例應用程式 ctrltest 將說明如何使用多個自訂控制項。 請參閱 MFC 一般範例的原始程式碼 ctrltest 將和線上說明。
主控描繪控制項/功能表
Windows 提供支援主控描繪控制項和功能表藉由使用 Windows 訊息。 父視窗的任何控制項或功能表會收到這些訊息和呼叫的函式,以回應。 您可以覆寫這些函式來自訂的視覺外觀和行為主控描繪控制項或功能表。
MFC 會直接支援主控描繪具有下列功能:
您可以覆寫這些函式,在您CWnd衍生的類別來實作自訂繪製的行為。
這種方法不會導致重複使用程式碼。 如果您有兩個類似的控制項中兩個不同CWnd類別,您必須在兩個位置來實作自訂控制項行為。 MFC 支援自繪控制項架構可解決這個問題。
Self-Draw 控制項和功能表
MFC 提供的預設實作 (在CWnd和 CMenu 類別) 的一般主控描繪的訊息。 這項預設實作會解碼主控描繪參數,並委派至控制項或功能表的擁有者繪製訊息。 因為繪圖的程式碼的控制項或功能表中的,不是在主控視窗的類別中,這就稱為 self-draw。
您可以使用 self-draw 控制項來建立使用主控描繪的語意,以顯示控制項的可重複使用的控制項類別。 繪製控制項的程式碼位於控制項類別,而不是其父代。 這是一個自訂控制項的程式設計物件導向的方法。 將下列清單的函式加入至您的 self-draw 類別:
Self-draw 的按鈕:
CButton:DrawItem(LPDRAWITEMSTRUCT); // insert code to draw this button
對於 self-draw 的功能表:
CMenu:MeasureItem(LPMEASUREITEMSTRUCT); // insert code to measure the size of an item in this menu CMenu:DrawItem(LPDRAWITEMSTRUCT); // insert code to draw an item in this menu
Self-draw 的清單方塊:
CListBox:MeasureItem(LPMEASUREITEMSTRUCT); // insert code to measure the size of an item in this list box CListBox:DrawItem(LPDRAWITEMSTRUCT); // insert code to draw an item in this list box CListBox:CompareItem(LPCOMPAREITEMSTRUCT); // insert code to compare two items in this list box if LBS_SORT CListBox:DeleteItem(LPDELETEITEMSTRUCT); // insert code to delete an item from this list box
Self-draw 的下拉式方塊中:
CComboBox:MeasureItem(LPMEASUREITEMSTRUCT); // insert code to measure the size of an item in this combo box CComboBox:DrawItem(LPDRAWITEMSTRUCT); // insert code to draw an item in this combo box CComboBox:CompareItem(LPCOMPAREITEMSTRUCT); // insert code to compare two items in this combo box if CBS_SORT CComboBox:DeleteItem(LPDELETEITEMSTRUCT); // insert code to delete an item from this combo box
如需詳細資訊,在主控描繪結構上 (DRAWITEMSTRUCT, MEASUREITEMSTRUCT, COMPAREITEMSTRUCT,以及 DELETEITEMSTRUCT) 請參閱 MFC 文件CWnd::OnDrawItem, CWnd::OnMeasureItem, CWnd::OnCompareItem,以及CWnd::OnDeleteItem分別。
使用 self-draw 控制項和功能表
對於 self-draw 的功能表,您必須覆寫兩者OnMeasureItem和OnDrawItem方法。
Self-draw 的清單方塊和下拉式方塊中,您必須覆寫OnMeasureItem和OnDrawItem。 您必須指定LBS_OWNERDRAWVARIABLE樣式的清單方塊或CBS_OWNERDRAWVARIABLE樣式下拉式方塊在對話方塊範本。 OWNERDRAWFIXED樣式不適用於 self-draw 項目因為之前 self-draw 控制項附加至清單方塊中,會判定固定的項目高度。 (您可以使用的方法CListBox::SetItemHeight和CComboBox::SetItemHeight而無法克服這項限制。)
切換至OWNERDRAWVARIABLE樣式會強制系統套用NOINTEGRALHEIGHT控制項的樣式。 由於控制項無法計算整數類資料的高度,以調整大小的變數項目的預設樣式的INTEGRALHEIGHT會被略過而且控制項永遠都是NOINTEGRALHEIGHT。 如果您的項目固定的高度,您可以防止部分項目所指定控制項大小的整數加成的項目大小來繪製。
為清單方塊和下拉式方塊和 self-drawing LBS_SORT或CBS_SORT樣式,必須覆寫OnCompareItem方法。
為清單方塊和下拉式方塊中,self-drawing OnDeleteItem未通常覆寫。 您可以覆寫OnDeleteItem如果您想要執行任何特殊的處理。 其中,這或許是適用的其中一種情況時,額外的記憶體或其他資源會儲存每個清單方塊或下拉式方塊項目。
Self-Drawing 控制項和功能表的範例
MFC 一般範例 ctrltest 將提供 self-draw 的功能表和 self-draw 的清單方塊的範例。
自繪] 按鈕的最常見的範例是一個點陣圖按鈕。 點陣圖按鈕是一個按鈕,顯示不同狀態的一、 兩個或三個點陣圖影像。 例如,所提供的 MFC 類別 CBitmapButton。
動態的子類別化
有時候會想要變更的物件已經存在的功能。 前述範例需要您先建立自訂控制項。 動態的子類別化可讓您自訂已建立的控制項。
子類別化是 Windows 名詞,表示取代 WndProc 與自訂視窗的WndProc ,呼叫舊WndProc的預設功能。
這不應該與 C++ 類別的衍生混淆。 以釐清,C++ 條款基底類別 和 衍生的類別 類似於 超級類別 和 子類別化 Windows 物件模型中。 使用 MFC 和視窗的子類別化的 C++ 衍生都是功能類似,但 C++ 不支援動態的子類別化。
CWnd類別會提供 C++ 物件之間的連線 (衍生自CWnd) 和 Windows window 物件 (稱為HWND)。
有三種常見的方式,這些相關:
CWnd會建立HWND。 您可以修改在衍生類別中的行為,藉由建立衍生自CWnd。 HWND會呼叫您的應用程式時,會建立CWnd::Create。
應用程式附加CWnd到現有HWND。 就不會修改現有的視窗的行為。 這是委派的大小寫,而且有賴於藉由呼叫CWnd::Attach到別名現有HWND到CWnd物件。
CWnd附加到現有的HWND ,而且您可以修改在衍生類別中的行為。 這就稱為動態子類別化,因為我們正在變更其行為,因此在 run time Windows 物件的類別,項目。
您可以使用的方法來達成動態子類別化CWnd::SubclassWindow和CWnd::SubclassDlgItem。
這兩種常式所附加CWnd到現有的物件HWND。 SubclassWindow會使用HWND直接。 SubclassDlgItem是 helper 函式可接受的控制項 ID,並在父視窗。 SubclassDlgItem專為附加從對話方塊範本所建立的對話方塊控制項的 C++ 物件。
請參閱 ctrltest 將的幾個範例的使用時機的範例SubclassWindow和SubclassDlgItem。