MFC之自繪控件


 

在描繪MFC界面時,MFC自帶的控件樣式是絕對不滿足界面的需求的。

所以我們就要在MFC自帶控件基礎上對控件樣式進行重繪。

在采用自繪前界面樣式

 

采用自繪后界面樣式

 

是不是自繪控件后看起來正常了很多?

自繪控件的步驟:

我們以做一個關閉按鈕為例

  1. 先創建一個MFC類繼承自CButton。
  2. 給這個類添加 一個虛函數DrawItem(),一個虛函數PreSubclassWindow()和 一個afx BOOL OnEraseBkgnd()函數(一般以afx開頭的函數都會在消息映射里面有一條映射)
  3. 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 }

     

  4. 添加OnEraseBkgnd()函數代碼,一般都是固定的

    BOOL CDhsButton::OnEraseBkgnd(CDC* pDC)
    {
    
        return TRUE;
    
    }

     

     

     

  5. 添加虛函數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.添加按鈕事件:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM