实现方法:先建一个自定义类继承CButtoon类,重载一些消息和函数。
1. 设置数据成员:
private:
BOOL m_bMouseMove;//鼠标是否在按钮上
public:
int m_nStyle;//有外部设置按钮为几态
Gdiplus::Image* m_pImage;//按钮图片
2. 设置成员函数
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CXXXButton)
public:
virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);//重载自绘制
//}}AFX_VIRTUAL
protected:
//{{AFX_MSG(CXXXButton)
afx_msg void OnMouseMove(UINT nFlags, CPoint point);//重载WM_MOUSEMOVE消息
afx_msg LRESULT OnMouseLeave(WPARAM wParam, LPARAM lParam); //重载WM_MOUSELEAVE消息
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
private:
CSize GetImageBlockSize() const;//通过m_nStyle和图片的大小来得到每次需要得到的图片的长和宽
BOOL TrackMouseEventEx(HWND hWnd, DWORD flags = TME_LEAVE, DWORD hoverTime = HOVER_DEFAULT); // 追踪鼠标事件
3. 构造函数的实现
CXXXButton::CXXXButton()
{
m_bMouseMove = false;//默认设置鼠标不再按钮上
}
4. 消息的定义
BEGIN_MESSAGE_MAP(CXXXButton, CButton)
//{{AFX_MSG_MAP(CXXXButton)
ON_WM_MOUSEMOVE()
ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
5. 个函数的实现
void CXXXButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
UINT uStyle = DFCS_BUTTONPUSH;
// This code only works with buttons.
ASSERT(lpDrawItemStruct->CtlType == ODT_BUTTON);
CRect imgRc;
CRect txtRc = lpDrawItemStruct->rcItem;
CRect dstRc = lpDrawItemStruct->rcItem;
COLORREF textColor = RGB(77,77,77);
CSize block = GetImageBlockSize();
if (lpDrawItemStruct->itemState & ODS_DISABLED) //按钮不可用状态
{
textColor = RGB(77,77,77);
imgRc = CRect(block.cx*(m_nStyle - 1), 0, block.cx*m_nStyle, block.cy);
}
else if (lpDrawItemStruct->itemState & ODS_SELECTED) //按钮按下状态
{
textColor = RGB(77,77,77); //设置文字颜色
imgRc = CRect(block.cx,0,2*block.cx,block.cy);//设置按钮的图片在Load的图片上面的位置
}
else
{
if(!m_bMouseMove) //鼠标不在按钮上面
{
textColor = RGB(77,77,77);
imgRc = CRect(0,0,block.cx,block.cy);
}
Else //鼠标在按钮上面
{
textColor = RGB(255,255,255);
imgRc = CRect(block.cx*2, 0, block.cx*3, block.cy);
}
}
//Draw the Background
CDC* dcMem = CDC::FromHandle(lpDrawItemStruct->hDC);
Graphics grap(dcMem->GetSafeHdc());
grap.DrawImage(m_pImage, Rect(dstRc.top,dstRc.left,dstRc.Width(),dstRc.Height()),
imgRc.left,imgRc.top,imgRc.Width(),imgRc.Height(),UnitPixel);
// Get the button's text.
CString strText;
GetWindowText(strText);
// Draw the button text using the text color red.
SetBkMode(lpDrawItemStruct->hDC,TRANSPARENT);
COLORREF crOldColor = ::SetTextColor(lpDrawItemStruct->hDC, textColor);
::DrawText(lpDrawItemStruct->hDC, strText, strText.GetLength(),
&lpDrawItemStruct->rcItem, DT_SINGLELINE|DT_VCENTER|DT_CENTER);
::SetTextColor(lpDrawItemStruct->hDC, crOldColor);
}
void CXXXButton::SizeToContent()
{
CRect rc;
GetWindowRect(&rc);
CSize block = GetImageBlockSize();
if(rc.Width() != block.cx || rc.Height() != block.cy)
{
SetWindowPos(NULL, -1, -1, block.cx, block.cy,
SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW|SWP_NOACTIVATE);
}
}
CSize CXXXButton::GetImageBlockSize() const
{
CSize block;
block.cy = m_pImage->GetHeight();
block.cx = m_pImage->GetWidth()/m_nStyle;
return block;
}
void CXXXButton::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
if(!m_bMouseMove)
{
TrackMouseEventEx(m_hWnd);
m_bMouseMove = TRUE;
Invalidate();
}
CButton::OnMouseMove(nFlags, point);
}
BOOL CXXXButton::TrackMouseEventEx(HWND hWnd, DWORD flags, DWORD hoverTime)
{
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(tme);
tme.hwndTrack = hWnd;
tme.dwFlags = flags;
tme.dwHoverTime = hoverTime;
return _TrackMouseEvent(&tme);
}
LRESULT CXXXButton::OnMouseLeave(WPARAM wParam, LPARAM lParam)
{
m_bMouseMove = FALSE;
Invalidate();
return LRESULT(0);
}
6. 应用
通过MFC产生一个按钮,将按钮的属性改为Owner draw,在ClassWizard中为按钮关联一个CButton对象,如m_btnMyButton;在头文件里面将按钮的类型CButton改为我们自绘制按钮类,CXXXButton。再在实现文件的构造函数里面定义自绘制按钮的参数,设置如下:
m_btnMyButton.m_nStyle = 3;
m_btnClearList.m_pImage = LoadImage();//自定义按钮图片
基本完成了。
注意:按钮的图标必须为三态或者四态,如: