www.pudn.com > mfc资源大全1.rar > flat_button2.shtml


 
 
 
 
    
    
   Controls - Flat-look Buttons 
 
 
 
 
 
 

Flat-look Buttons


This article was contributed by Roger Onslow.

Flat look (cool) toolbar buttons have been well covered. But what about including the same sort of button in a Dialog (or form or dialog bar)? This is not supported by the new common controls, so you have to do it yourself.

Here is a class that does flat-look buttons for you. Just like a toolbar, the buttons get borders when the mouse moves over them. The code uses DrawState to draw the buttons.

This class can be (I'll send further articles when I get some time :-) enhanced to include check-style, optional standard looks, icons as well as text, change cursor as mouse moves over, color change (for links), 3D text, size text to fit etc etc. But this is a good starting point :-)

 
class CMyFlatButton : public CButton { 
     DECLARE_DYNAMIC(CMyFlatButton) 
private: 
     bool m_bRaised; 
     bool m_bDrawBackground; 
public: 
     CMyFlatButton() 
          : CButton() 
          , m_bRaised(false)  // internal only 
          , m_bDrawBackground(true)      // internal only 
     {} 
 
     // drawing 
protected: 
     virtual void DrawText(CDC* pDC, const CRect& rect, LPCTSTR text, UINT state=0); 
     virtual void DrawBorders(CDC* pDC, CRect& rect, UINT state=0); 
     virtual void Draw(CDC* pDC, const CRect& rect, UINT state=0); 
 
protected: 
     //{{AFX_MSG(CMyFlatButton) 
     afx_msg BOOL OnEraseBkgnd(CDC* pDC); 
     afx_msg void OnMouseMove(UINT nFlags, CPoint point); 
     afx_msg LONG OnMouseLeave(WPARAM, LPARAM); 
     //}}AFX_MSG 
     //{{AFX_VIRTUAL(CMyFlatButton) 
     virtual void PreSubclassWindow(); 
     virtual void DrawItem(LPDRAWITEMSTRUCT lpDIS); 
     //}}AFX_VIRTUAL 
     DECLARE_MESSAGE_MAP(); 
}; 
 
/////////////////////////////////////////////////////////////////////////// 
// 
BEGIN_MESSAGE_MAP(CMyFlatButton, CButton) 
//{{AFX_MSG_MAP(CMyFlatButton) 
ON_WM_ERASEBKGND() 
ON_WM_MOUSEMOVE() 
ON_MESSAGE(WM_MOUSELEAVE,OnMouseLeave) 
//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
IMPLEMENT_DYNAMIC(CMyFlatButton,CButton) 
 
 
// this routine uses DrawState to draw the text approriately. 
// it automatically centres the text within the button border 
 
void CMyFlatButton::DrawText(CDC* pDC, const CRect& rect, LPCTSTR text, UINT state) { 
     // we want transparent text 
     int nBkModeOld = pDC->SetBkMode(TRANSPARENT); 
     // setup text color 
     COLORREF textcol = ::GetSysColor(COLOR_BTNTEXT); 
     COLORREF oldTextColor = pDC->SetTextColor(textcol); 
     // centre the text 
     CSize textSizeClient = pDC->GetTextExtent(text,strlen(text)); 
     int x = rect.left+(rect.Width()-textSizeClient.cx)/2; 
     int y = rect.top+(rect.Height()-textSizeClient.cy)/2; 
     // draw the text 
     pDC->DrawState(CPoint(x,y), rect.Size(), text, 
          (state & ODS_DISABLED?DSS_DISABLED:DSS_NORMAL), true, 0, (HBRUSH)NULL 
          ); 
     // restore dc 
     pDC->SetTextColor(oldTextColor); 
     pDC->SetBkMode(nBkModeOld); 
} 
 
 
// this routine (optionally) draws the borders on the button 
// flat buttons use only single-pixel borders, so we cannot use 
// DrawFrameControl. 
 
void CMyFlatButton::DrawBorders(CDC* pDC, CRect& rect,UINT state) { 
     if (state & ODS_SELECTED) { 
          pDC->Draw3dRect(rect,::GetSysColor(COLOR_3DSHADOW), 
                               ::GetSysColor(COLOR_3DHILIGHT)); 
          rect.DeflateRect(1,1); 
     } else if (! m_bRaised && ! (state & ODS_FOCUS)) { 
          // no border - flat look 
          rect.DeflateRect(1,1); 
     } else { 
 
          pDC->Draw3dRect(rect,::GetSysColor(COLOR_3DHILIGHT), 
                               ::GetSysColor(COLOR_3DSHADOW)); 
          rect.DeflateRect(1,1); 
     } 
     rect.DeflateRect(1,1); 
     if (state & ODS_SELECTED) { 
          rect.OffsetRect(1,1);    // offset image when pressed 
     } 
} 
 
 
// Here we draw the appropriate parts of the button 
 
void CMyFlatButton::Draw(CDC* pDC, const CRect& inrect, UINT state) { 
     CRect rect = inrect; 
     DrawBorders(pDC,rect,state); 
     CString text; 
     GetWindowText(text); 
     if (! text.IsEmpty()) { 
          DrawText(pDC,rect,text,state); 
     } 
} 
 
// Overrides 
void CMyFlatButton::PreSubclassWindow() { 
     SetButtonStyle(GetButtonStyle() | BS_OWNERDRAW | BS_NOTIFY); 
} 
 
 
// we use m_bDrawBackground flag to allow us to 
// repaint behind the button before drawing on top 
 
void CMyFlatButton::DrawItem(LPDRAWITEMSTRUCT lpDIS) { 
     if (m_bDrawBackground) { 
          m_bDrawBackground = false; 
          // if not redrawing the whole thing, 
          CWnd* pParent = GetParent(); 
          CRect rect; GetWindowRect(rect); 
          pParent->ScreenToClient(rect); 
          pParent->InvalidateRect(rect); 
          pParent->UpdateWindow(); 
     } else { 
          m_bDrawBackground = true; 
          CDC* pDC = CDC::FromHandle(lpDIS->hDC); 
          ASSERT_VALID(pDC); 
          CRect rectClient = lpDIS->rcItem; 
          Draw(pDC,rectClient,lpDIS->itemState); 
     } 
} 
 
// Messages 
BOOL CMyFlatButton::OnEraseBkgnd(CDC*) { 
     return true;    // we don't do any erasing when owner drawn 
} 
 
 
// the m_bRaised flag inidicates whether or not to 
// draw the borders.  If the mouse is over the button 
// the borders are drawn.  We use TrackMouseEvent to 
// detect when the mouse leaves the button so we can 
// turn off the flag 
 
void CMyFlatButton::OnMouseMove(UINT, CPoint) { 
     if (! m_bRaised) { 
          // draw with button borders 
          m_bRaised = true; 
          Invalidate(); 
          // remember to remove button borders when we leave 
          TRACKMOUSEEVENT trackmouseevent; 
          trackmouseevent.cbSize = sizeof(trackmouseevent); 
          trackmouseevent.dwFlags = TME_LEAVE; 
          trackmouseevent.hwndTrack = GetSafeHwnd(); 
          trackmouseevent.dwHoverTime = HOVER_DEFAULT; 
          _TrackMouseEvent(&trackmouseevent); 
     } 
} 
 
LONG CMyFlatButton::OnMouseLeave(WPARAM, LPARAM) { 
     // remove button borders 
     m_bRaised = false; 
     Invalidate(); 
     return 0; 
} 

Last updated: 13 May 1998


Goto HomePage
© 1998 Zafir Anjum 
Contact me: zafir@home.com