在描繪MFC界面時,MFC自帶的控件樣式是絕對不滿足界面的需求的。
所以我們就要在MFC自帶控件基礎上對控件樣式進行重繪。

在采用自繪前界面樣式

采用自繪后界面樣式
是不是自繪控件后看起來正常了很多?
自繪控件的步驟:
我們以做一個關閉按鈕為例
- 先創建一個MFC類繼承自CButton。
- 給這個類添加 一個虛函數DrawItem(),一個虛函數PreSubclassWindow()和 一個afx BOOL OnEraseBkgnd()函數(一般以afx開頭的函數都會在消息映射里面有一條映射)
-
DrawItem()是控件的自繪處理函數,在這個函數中可以對控件的樣式進行描繪。
附一段代碼為例:
1 void CDhsButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) 2 { 3 CDC* pDC= CDC::FromHandle(lpDrawItemStruct->hDC); 4 CRect rect = &lpDrawItemStruct->rcItem; 5 UINT uID = lpDrawItemStruct->CtlID; 6 7 Graphics g(pDC->m_hDC); 8 g.SetSmoothingMode(SmoothingModeHighQuality); 9 10 11 if (::GetWindowLong(m_hWnd, GWL_STYLE) & WS_DISABLED) 12 { 13 if (m_pImageDisable != NULL) 14 g.DrawImage(m_pImageDisable, 0, 0, rect.Width(), rect.Height()); 15 else 16 g.DrawImage(m_pImageNormal, 0, 0, rect.Width(), rect.Height()); 17 } 18 else if (m_nMouseState == Down) 19 { 20 if (m_pImageOver != NULL) 21 g.DrawImage(m_pImageOver, 0, 0, rect.Width(), rect.Height()); 22 else 23 g.DrawImage(m_pImageNormal, 0, 0, rect.Width(), rect.Height()); 24 } 25 else if (m_bSelected) 26 { 27 if (m_pImageSelected != NULL) 28 g.DrawImage(m_pImageSelected, 0, 0, rect.Width(), rect.Height()); 29 else 30 g.DrawImage(m_pImageNormal, 0, 0, rect.Width(), rect.Height()); 31 } 32 else 33 { 34 g.DrawImage(m_pImageNormal, 0, 0, rect.Width(), rect.Height()); 35 } 36 37 if (!m_strCaption.IsEmpty()) 38 { 39 rect.left += 5; 40 41 if (::GetWindowLong(m_hWnd, GWL_STYLE) & WS_DISABLED) 42 { 43 PublicFun::GDIDrawText(pDC, m_strCaption, rect, m_pFont, RGB(120, 120, 120), FALSE, TRUE); 44 } 45 else if (m_bSelected) 46 { 47 PublicFun::GDIDrawText(pDC, m_strCaption, rect, m_pFont, RGB(0, 0, 0), FALSE, TRUE); 48 } 49 else if (m_nMouseState == Over) 50 { 51 PublicFun::GDIDrawText(pDC, m_strCaption, rect, m_pFont, RGB(0, 0, 0), FALSE, TRUE); 52 } 53 else 54 { 55 PublicFun::GDIDrawText(pDC, m_strCaption, rect, m_pFont, RGB(0, 0, 0), FALSE, TRUE); 56 } 57 } 58 59 ReleaseDC(pDC); 60 }
-
添加OnEraseBkgnd()函數代碼,一般都是固定的
BOOL CDhsButton::OnEraseBkgnd(CDC* pDC) { return TRUE; }
-
添加虛函數PreSubclassWindow函數代碼(PreSubclassWindow函數實際上是在CWnd::CeateEx方法中的 AfxHookWindowCreate(this)方法中實現的,AfxHookWindowCreate作用是設置鈎子函數,所以你如果想在創建窗口之前將窗口與自己的派生類進行關聯,這時候建立前的處理就要在PreSubclassWindow中寫。)
具體來說,
- 如果你定義一個窗口(如CButton派生類CMyButton),然后使用對話框數據交換比如通過DDX將一個按鈕與自己的派生類對象關聯,這時候,一些"建立前"的處理就應該寫在"PreSubclassWindow"中。
- 如果你用的不是"對話框數據關聯",而是在OnInitDialg中自己創建.這時候,一些"建立前"的處理就應該寫在 "PreCreateWindow"中。)
在PreSubclassWindow函數中,設置ModifyStyle(0, BS_OWNERDRAW);
代碼如下
1 void CDhsButton::PreSubclassWindow() 2 { 3 ModifyStyle(0, BS_OWNERDRAW); 4 5 CButton::PreSubclassWindow(); 6 }
使用BS_OWNERDRAW屬性 是要求創建CButton的繼承類,並在其中重載DrawItem方法才可以。你要是不想改變Button的外觀不要用這個屬性。
意思就是如果你要重載派生類按鈕中的DrawItem方法,必須要設置了BS_OWNERDRAW 才能重載
6.因為是通過DDX關聯的方式,所以在使用上,要用DoDataExchange方法將派生類與資源中的按鈕進行關聯。
7.添加按鈕事件:
