#pragma once // FButton class FButton : public CButton { DECLARE_DYNAMIC(FButton) public: //按钮的状态 BOOL m_bOver; //鼠标位于按钮之上时该值为true,反之为flase BOOL m_bTracking; //在鼠标按下没有释放时该值为true BOOL m_bSelected; //按钮被按下是该值为true BOOL m_bFocus; //按钮为当前焦点所在时该值为true FButton(UINT nID); virtual ~FButton(); CPen m_OutBorderPen; Image *image; bool ImageFromIDResource(UINT nID, LPCTSTR sTR,Image *&pImg);//从图片资源ID中装载图像到Image类的指针对象 afx_msg void OnMouseMove(UINT nFlags, CPoint point); afx_msg LRESULT OnMouseLeave(WPARAM wParam, LPARAM lParam); afx_msg LRESULT OnMouseHover(WPARAM wParam, LPARAM lParam); virtual void DrawItem(LPDRAWITEMSTRUCT /*lpDrawItemStruct*/); afx_msg BOOL OnEraseBkgnd(CDC* pDC); protected: DECLARE_MESSAGE_MAP() virtual void PreSubclassWindow(); };
// FButton.cpp : 实现文件 // #include "stdafx.h" #include "TuDai.h" #include "FButton.h" // FButton IMPLEMENT_DYNAMIC(FButton, CButton) FButton::FButton(UINT nID) { #ifndef _WIN32_WCE EnableActiveAccessibility(); #endif //m_BoundryPen.CreatePen(PS_INSIDEFRAME | PS_SOLID, 1, RGB(55, 98, 6)); ImageFromIDResource(nID,L"PNG",image); } FButton::~FButton() { } BEGIN_MESSAGE_MAP(FButton, CButton) ON_WM_MOUSEMOVE() ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave) ON_MESSAGE(WM_MOUSEHOVER, OnMouseHover) ON_WM_ERASEBKGND() END_MESSAGE_MAP() // FButton 消息处理程序 void FButton::OnMouseMove(UINT nFlags, CPoint point) { if(!m_bTracking) //定义的一个标志变量,如果已经注册了就不需要再次注册,直到这两个消息中有人响应了 { //再注册 TRACKMOUSEEVENT v_tme; v_tme.cbSize = sizeof(v_tme); v_tme.hwndTrack = m_hWnd; //指明的是哪个控件 v_tme.dwFlags = TME_LEAVE | TME_HOVER; //离开和延时两个消息 v_tme.dwHoverTime = 1; //指鼠标在控件上停留多少时间后才会响应停留消息OnMouseLeave m_bTracking = _TrackMouseEvent(&v_tme); //注册消息,响应完成后要再次注册,否则响应一次后就不响应 } HCURSOR hCur = LoadCursor( NULL , IDC_HAND ) ; ::SetCursor(hCur); CButton::OnMouseMove(nFlags, point); } LRESULT FButton::OnMouseLeave(WPARAM wParam, LPARAM lParam) { //if (m_bOver == true) { m_bOver = false; m_bTracking = false; Invalidate(); //} CRect rect; GetWindowRect(&rect); GetParent()-> ScreenToClient(&rect); GetParent()-> InvalidateRect(&rect); /*InvalidateRect(NULL, FALSE); */ return 0; } LRESULT FButton::OnMouseHover(WPARAM wParam, LPARAM lParam) { //if (m_bOver == false) { m_bOver = true; m_bTracking = true; Invalidate(); //} CRect rect; GetWindowRect(&rect); GetParent()-> ScreenToClient(&rect); GetParent()-> InvalidateRect(&rect); return 0; } void FButton::PreSubclassWindow() { CButton::PreSubclassWindow(); m_bTracking = false; m_bOver = false; ModifyStyle(0, BS_OWNERDRAW); } bool FButton::ImageFromIDResource(UINT nID, LPCTSTR sTR,Image *&pImg)//从图片资源ID中装载图像到Image类的指针对象 //特别说明:参数3中使用了指针引用,使得传入的参数(指针)在函数中可以改变其地址(例如本函数),也可以将指针引用改为指针的指针, //如Image **pImg,当然其他有关pImg的引用也需要做出相应的更改。 { HINSTANCE hInst = AfxGetResourceHandle();//利用这个函数返回的HINSTANCE句柄来直接访问应用程序的句柄,例如,在调用Windows函数FindResource时使用 HRSRC hRsrc = ::FindResource (hInst,MAKEINTRESOURCE(nID),sTR); //该函数确定指定模块中指定类型和名称的资源所在位置 if (!hRsrc) return FALSE; DWORD len = SizeofResource(hInst, hRsrc);//该函数返回指定资源字节数大小。 BYTE* lpRsrc = (BYTE*)LoadResource(hInst, hRsrc);//该函数装载指定资源到全局存储器,返回值是相关资源的数据的句柄 if (!lpRsrc) return FALSE; HGLOBAL m_hMem = GlobalAlloc(GMEM_FIXED, len);//分配一个全局内存块 //GlobalAlloc是winxx的一个api函数,new是c++的一个操作符。 //new可以根据操作系统有不同的实现,但是无论他怎么实现,在一个进程中开辟的内存只有该进程才能访问。 //但是GlobalAlloc不同,在一个进程中创建的内存,可以被其他进程调用。这就是GlobalAlloc的全局概念,和new是不一样的。 //使用new和delete对一个进程中的两个模块进行跨模块的内存开辟和释放,程序可能被崩溃,使用GlobalAlloc开辟内存不存在这个问题。 //一般除了在剪贴板等函数中使用GlobalAlloc函数返回的句柄外,在其它地方使用GlobalAlloc函数的地方不多啊。 BYTE* pmem = (BYTE*)GlobalLock(m_hMem);//锁定内存块,该函数接受一个内存句柄作为参数,然后返回一个指向被锁定的内存块的指针,您可以用该指针来读写内存。 memcpy(pmem,lpRsrc,len);//由lpRsrc所指内存区域复制len个字节到pmem所指内存区域 IStream* pstm; CreateStreamOnHGlobal(m_hMem,FALSE,&pstm);//在全局内存块(m_hMem)中创建一个流对象(pstm),第二个参数为flase时,则不再使用流(pstm)时需要调用pstm->Release() //如果为true时,则系统会自动释放该流(pstm) pImg=Gdiplus::Image::FromStream(pstm);//在流对象(pstm)的基础上建立一个image对象,返回对象的指针 GlobalUnlock(m_hMem);//调用GlobalUnlock函数来解锁先前被锁定的内存,该函数使得指向内存块的指针无效。 pstm->Release(); //释放流对象 FreeResource(lpRsrc); //释放资源数据指针 return true; } void FButton::DrawItem(LPDRAWITEMSTRUCT lpDS) { CRect Rect; UINT W = image->GetWidth(),H = image->GetHeight(); GetClientRect(&Rect); Graphics g(lpDS->hDC); Bitmap bmp(Rect.Width(),Rect.Height()); Graphics* gs = Graphics::FromImage(&bmp); if(lpDS->itemState & ODS_SELECTED)//按钮按下 { gs->DrawImage(image,(0 - Rect.Width() * 2),0,W,H); } else if(m_bOver)//鼠标移上 { gs->DrawImage(image,(0 - Rect.Width()),0,W,H); } else//普通形态 { gs->DrawImage(image,0,0,W,H); } delete gs; g.DrawImage(&bmp,0,0); g.ReleaseHDC(lpDS->hDC); } BOOL FButton::OnEraseBkgnd(CDC* pDC) {return true; }