VC中自畫控件的過程和方法(CButton, CEdit, etc)

轉自:http://hi.baidu.com/jjzhang166/blog/item/9da841df83761919495403b6.html

Windows自帶控件的樣式太過單調,爲了界面美觀一些很多時候需要自己繪製,譬如 按鈕,編輯框,組合框等。
自己總結過程如下:
1.生成一個以要重繪的空間類爲基類的派生類。(我想重繪CButton, 則應該生成一個CMyButton : public CButton。
2.在派生類裏面重載DrawItem虛函數(如果該類中沒有DrawItem需函數,可以加入WM_NCPAINT消息來代替,在消息的執行體內繪製)
DrawItem虛函數是一個專門用來重繪自畫空間的函數,且該函數只能用在派生類中!我們可以重寫函數體,在裏面完成對控件的定製繪製。
DrawItem函數的調用要求控件的屬性是" Owner Draw", 我們當然可以在資源對話框的屬性裏面設置空件爲"OwnerDraw"屬性,但更好的方法是在PreSubclassWindow()中進行。注意:不要和PreCreateWindow()函數混了,後者中執行ModifyStyle()函數不起效果。
當CWnd::Create()或DDX_Control被調用後,這兩個函數都會調用SubClassWindow(), SubClassWindow()緊接着會調用PreSubclassWindow(),我們可以在該函數內設置控件的屬性爲"OwnerDraw"

/////////
void CMyButton::PreSubclassWindow()
{
CButton::PreSubclassWindow();

ModifyStyle(0, BS_OWNERDRAW); // make the button owner drawn
}

3.子類化重繪類。
有三種方法都可以實現子類化,主要是:
(1)在創建過程中用DDX子類化一個類。
具體就是在ClassWizard裏爲對應的對話框內的CButton創建一個類型爲CMyButton的變量。
CMyButton m_myButton;
這樣, 對話框的DoDataExchange會創建一個DDX_Control調用。DDX_Control會調用SubClassWindow, 這樣就可以使得你的按鈕實用CMyButton的消息處理,而不用CButton的。

(2)實用一個不被ClassWizard支持的類子類化一個控件。

假如你的項目中已經加入了一個窗口類,你想子類化該類類型的一個對象,但是ClassWizard並不提供給你這種類類型,這時你就需要重建ClassWizard文件。

首先備份以下項目下的.clw文件到一個別的目錄下,然後刪除項目目錄下的.clw文件,然後點擊Ctrl+W,這時會彈出一個對話框讓你選擇你想包含的類。如果沒有選擇你的新類,你可以自己到頭文件裏手動修改父類爲子類(譬如把CButton 修改爲CMyButton)
(3)子類化一個已經存在的窗口類。
用DDX子類化一個類非常簡單,但如果我們想子類化的是一個已經存在的類的時候,這種方法就不適合了。例如我們想子類化一個組合框內的編輯框控件,則你需要事先把組合框創建好。
這種情況下,你可以使用方便的SubclassDlgItem()或SubclassWindow()函數來完成。這兩個函數允許你動態的子類化一個類, 也就是他們可以使你的的新類類型的對象依附於一個已經存在的窗口。
例如假設我們有一個對話框,上面有一個ID爲ID_BUTTON1的按鈕控件,這個控件早已經創建成功存在於對話框了,而我們想把這個按鈕跟一個CMyButton類的對象建立聯繫,從而使得這個按鈕控件表現出CMyButton定義的行爲。
(a)首先我們需要定義一個CMyButton類的對象,這個對象定義爲對話框或者視圖類(View)的變量就比較合適。
CMyButton m_btnButton;
定義好變量後, 我們可以在對話框的OnInitialDialog()(或者別的合適的地方也可以)調用:
m_btnButton.SubclassDlgItem(IDC_BUTTON1, this);
完成子類化。
(b)如果你不想使用SubclassDlgItem,也可以這樣子類化。假設你已經獲得了一個指向我們想子類化控件類的指針(譬如這裏就是一個指向IDC_BUTTON1所標識的按鈕的指針),如果你是在視圖類(View)或者別的從CWnd繼承來的類裏面來完成控件的動態創建,你可以這樣:
CWnd* pWnd = GetDlgItem(IDC_BUTTON1); // or use some other method to get
// a pointer to the window you wish
// to subclass
ASSERT( pWnd && pWnd->GetSafeHwnd() );
m_btnMyButton.SubclassWindow(pWnd->GetSafeHwnd());
完成子類化過程。
總上,子類化並不難,你只需要認真的選擇你需要子類化的類,並且清楚你想自己處理的消息是什麼並處理他們。清楚你要子類化的類都有哪些虛擬函數並重寫他們。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章