我们要举的例子是利用一张包含按钮的三种状态(鼠标移动,鼠标离开,鼠标单击)的位图来绘制按钮,因为三种状态 在一张位图上,所以每种状态的图片高度都相等,而宽度是位图总长度的1/3。
1.首先创建一个CBitmapButton的子类CHoverButton,并创建四个类成员变量: //指示鼠标是否在按钮上面 BOOL m_bHover; //按钮是否跟踪到鼠标 BOOL m_bTracking; //保存图片的变量 CBitmap mybitmap; //按钮尺寸 CSize m_ButtonSize; 2.在类的构造函数中,初始化和鼠标相关的变量 CHoverButton::CHoverButton() { m_bHover = FALSE; m_bTracking = FALSE; }
3.创建一个载入位图的成员函数,参数为位图的资源标识符。在按钮自绘之前,必须有相应的位图已经载入。 BOOL LoadBitmap(UINT bitmapid); 其实现为: BOOL CHoverButton::LoadBitmap(UINT bitmapid) { //载入图片 mybitmap.Attach(::LoadImage(::AfxGetInstanceHandle(),MAKEINTRESOURCE(bitmapid), IMAGE_BITMAP,0,0,LR_LOADMAP3DCOLORS)); BITMAP bitmapbits; //获取位图信息并存入bitmapbits结构中 mybitmap.GetBitmap(&bitmapbits); //取位图相应的高度和1/3宽度。 m_ButtonSize.cy=bitmapbits.bmHeight; m_ButtonSize.cx=bitmapbits.bmWidth/3; SetWindowPos( NULL, 0,0, m_ButtonSize.cx,m_ButtonSize.cy,SWP_NOMOVE |SWP_NOOWNERZORDER ); return TRUE; } 4.重载按钮的虚拟函数DrawItem()成员函数 当一个自绘按钮的外观发生变化时由框架调用.其函数原型为: virtual void DrawItem( LPDRAWITEMSTRUCT lpDrawItemStruct ); DRAWITEMSTRUCT结构包含被绘制项目的信息。 下面是该函数的实现 void CHoverButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) { //获取保存在DRAWITEMSTRUCT结构中且在绘制按钮时必须使用的设备上下文 CDC* mydc=CDC::FromHandle(lpDrawItemStruct->hDC);
//创建兼容的设备上下文 CDC* pMemDC = new CDC; pMemDC -> CreateCompatibleDC(mydc);
//保存旧对象 CBitmap * pOldBitmap; pOldBitmap = pMemDC -> SelectObject(&mybitmap); CPoint point(0,0); //判断按钮是否处于选择状态,如果是则绘制选择状态的按钮位图,在我们提供的位图中,选中状态的按钮图片是第二个 if(lpDrawItemStruct->itemState & ODS_SELECTED) { mydc->BitBlt(0,0,m_ButtonSize.cx,m_ButtonSize.cy,pMemDC,m_ButtonSize.cx,0,SRCCOPY); } else { //判断鼠标是否离开还是在按钮上面,以便绘制相应的位图 if(m_bHover) { mydc->BitBlt(0,0,m_ButtonSize.cx,m_ButtonSize.cy,pMemDC,m_ButtonSize.cx*2,0,SRCCOPY); }else { mydc->BitBlt(0,0,m_ButtonSize.cx,m_ButtonSize.cy,pMemDC,0,0,SRCCOPY); } }
// clean up pMemDC -> SelectObject(pOldBitmap); delete pMemDC; }
5.对于按钮的鼠标移动处理,我们可以使用其WM_MOUSEMOVE消息来处理,而对于按钮的鼠标悬停和离开消息,我们必须使用 TrackMouseEvent()函数来处理,该函数在鼠标指针离开窗体或悬停在窗体上是发送消息.可以发送的消息有(WM_MOUSELEAVE, WM_MOUSEHOVER,WM_NCMOUSELEAVE,WM_NCMOUSEHOVER)
该函数带有一个TRACKMOUSEEVENT结构参数,它包含跟踪鼠标的信息。 对于鼠标在按钮上移动,离开按钮,在按钮上悬停的处理代码如下:
void CHoverButton::OnMouseMove(UINT nFlags, CPoint point) { if (!m_bTracking) { TRACKMOUSEEVENT tme; tme.cbSize = sizeof(tme); tme.hwndTrack = m_hWnd; tme.dwFlags = TME_LEAVE|TME_HOVER; tme.dwHoverTime = 1; m_bTracking = _TrackMouseEvent(&tme); } CBitmapButton::OnMouseMove(nFlags, point); }
LRESULT CHoverButton::OnMouseLeave(WPARAM wparam, LPARAM lparam) { m_bTracking = FALSE; m_bHover=FALSE; //重画按钮 Invalidate(TRUE); return 0; }
LRESULT CHoverButton::OnMouseHover(WPARAM wparam, LPARAM lparam) {
m_bHover=TRUE; Invalidate(TRUE); return 0; }
6.我们把这个按钮放入对话框进行测试,首先在基于对话框的应用程序中加入一个按钮,设置其Owner Draw 的属性为true。然后添加一个按钮控件变量,然后用CHoverButton类代替CButton类 CHoverButton m_HoverButton; 最后在对话框的OnInitDialog()处理函数中加入下面一行代码来为按钮的自绘作准备: m_HoverButton.LoadBitmap(IDB_BITMAP1); 
|