范圣帅 - 卡农的魔笛

卡迪的快乐生活

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
#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;
}

 

posted on 2013-05-30 11:10  范圣帅  阅读(740)  评论(0编辑  收藏  举报