eVC下自绘按钮实现

按钮这个控件在软件中使用是非常广泛的,特别是基于MFC开发,按钮提供了很好的便捷。

但是在eVC下的按钮显示效果是非常土的,且背景颜色不好改。如果裁系统的时候将XP风格裁进去的话,默认按钮效果会好一些,但是背景颜色不好控制,在ce平台下,没有鼠标是很正常的,带XP风格的CE系统按钮提示不够明显,这个时候就需要自绘按钮了。

首先,先建立一个基于CWnd的类,如:CMyButton : public CWnd

1、添加成员变量:
 CDC  m_dcBack;
 CBitmap m_bmpBack; //背景
 COLORREF m_clNorBack;  //正常时背景颜色
 COLORREF m_clFocBack; //设上焦点时背景颜色
 COLORREF m_clNorText;
 COLORREF m_clFocText;
 bool    m_bLastState;          //最后一次状态,true =焦点
 CString m_strTitleInfo;        //按钮上字符

2、添加成员函数:
void InitMyButton(); //初始化按钮
void DrawBackForNor(); //默认
void DrawBackForFoc(); //按下去
void DrawBackForMid(); //中间
BOOL    CreateBTN(LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect,
         CWnd* pParentWnd, UINT nID,LPDealWithBTN lpDealWithBTN = NULL);//创建
void SetWindowText(LPCTSTR lpszString);//重载函数
BOOL    EnableWindow(BOOL bEnable = TRUE);//重载函数

3、在View里添加消息: 如果考虑到右键效果,可以参考LBUTTONDOWN()添加
ON_WM_SETFOCUS()
 ON_WM_KILLFOCUS()
 ON_WM_PAINT()
 ON_WM_LBUTTONDOWN()
 ON_WM_ENABLE()

上面的工作已经将基本工作完成了。接下来就是完成相应的代码了:

 

void  CMyButton::OnPaint() 
{
//    CPaintDC dc(this); // device context for painting
    
    
// TODO: Add your message handler code here
    CPaintDC dc(this); // device context for painting    
    
// TODO: Add your message handler code here
    CRect rectClient;
    GetClientRect(rectClient);
    
    CDC memDC ;
    CBitmap memBitmap ;
    CBitmap
* oldBitmap ; 
    
    memDC.CreateCompatibleDC(
&dc) ;
    memBitmap.CreateCompatibleBitmap(
&dc, rectClient.Width(), rectClient.Height()) ;
    oldBitmap 
= (CBitmap *)memDC.SelectObject(&memBitmap) ;
    
    
//将m_dcCoor和m_dcLine绘制到控件上
    if (memDC.GetSafeHdc() != NULL)
    
{
        memDC.BitBlt(
00, rectClient.Width(), rectClient.Height(), 
                     
&m_dcBack, 00, SRCCOPY) ;    
        
        dc.BitBlt(
00, rectClient.Width(), rectClient.Height(), 
            
&memDC, 00, SRCCOPY) ;
    }

    
    memDC.SelectObject(oldBitmap) ;    
    
    
//删除内存位图GDI对象
    memBitmap.DeleteObject();
    
//删除内存绘图环境
    memDC.DeleteDC();    
    
// Do not call CWnd::OnPaint() for painting messages
}

 

 

BOOL CMyButton::CreateBTN(LPCTSTR lpszWindowName, DWORD dwStyle,  const  RECT &  rect, 
                        CWnd
*  pParentWnd, UINT nID,LPDealWithBTN lpDealWithBTN /* = NULL*/
{
     
// TODO: Add your specialized code here and/or call the base class
     BOOL bresult ;
    
//注册窗体类
    static CString className = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW);
    
//创建窗体类
    bresult = CWnd::CreateEx(NULL, className, NULL, dwStyle, 
        rect.left, rect.top, rect.right
-rect.left, rect.bottom-rect.top,
        pParentWnd
->GetSafeHwnd(), (HMENU)nID) ;
    
    
//更新窗体显示
     if (bresult != 0)
    
{
        m_strTitleInfo 
= lpszWindowName;
        m_lpDealWithBTN 
= lpDealWithBTN;
         InitMyButton();    
        DrawBackForNor();
    }

    
return TRUE;
    
//    return CWnd::Create(lpszClassName, lpszWindowName, dwStyle, rect, pParentWnd, nID, pContext);
}



void  CMyButton::InitMyButton()
{
    CClientDC dc(
this);
//    CBrush brushBack;
    CRect  rect;
    GetClientRect(rect);
    
//    brushBack.CreateSolidBrush(m_clNorBack) ;
    
//创建画线设备环境以及创建相应缓冲区
    if (m_dcBack.GetSafeHdc() == NULL)
    
{
        m_dcBack.CreateCompatibleDC(
&dc) ;
        m_bmpBack.CreateCompatibleBitmap(
&dc, rect.Width(), rect.Height()) ;
        m_dcBack.SelectObject(
&m_bmpBack) ;
    }

    
    m_dcBack.SetBkColor (m_clNorBack) ;
    m_dcBack.FillSolidRect(rect,m_clNorBack);

}

 

 

void  CMyButton::DrawBackForFoc()
{
    CBrush bRushBack(m_clFocBack);
    CBrush 
*OldBrush = m_dcBack.SelectObject(&bRushBack);

    CPen penBlack;
    penBlack.CreatePen(PS_SOLID,
1,RGB(0,0,0));

    CPen 
*penOld = m_dcBack.SelectObject(&penBlack);

    CRect rect;
     GetClientRect(
&rect);

    m_dcBack.FillSolidRect(rect,RGB(
192,192,192));
//    rect.DeflateRect(5,5);
    m_dcBack.RoundRect(rect,CPoint(4,4));

    m_dcBack.SelectObject(OldBrush);
    m_dcBack.SelectObject(penOld);

    bRushBack.DeleteObject();
    penBlack.DeleteObject();

    
int nLenthBuf = WideCharToMultiByte(CP_ACP,0,m_strTitleInfo,-1,NULL,0,NULL,NULL) - 1;
    LONG lLeftX 
= rect.left + (rect.Width() - nLenthBuf * 6/ 2;
    LONG lLeftY 
= rect.top  + (rect.Height() - 14/ 2;

    m_dcBack.SetBkColor(m_clFocBack);
    m_dcBack.SetTextColor(m_clFocText);
    m_dcBack.ExtTextOut(lLeftX,lLeftY,ETO_OPAQUE,NULL,m_strTitleInfo,NULL);

    Invalidate(FALSE);
    m_bLastState 
= true;
}


void  CMyButton::DrawBackForMid()
{
    CBrush bRushBack(RGB(
230,230,207));
    CBrush 
*OldBrush = m_dcBack.SelectObject(&bRushBack);
    
    CPen penBlack;
    penBlack.CreatePen(PS_SOLID,
1,RGB(128,128,128));
    
    CPen 
*penOld = m_dcBack.SelectObject(&penBlack);
    
    CRect rect;
    GetClientRect(
&rect);
    
    m_dcBack.FillSolidRect(rect,RGB(
192,192,192));
    
//    rect.DeflateRect(5,5);
    m_dcBack.RoundRect(rect,CPoint(4,4));
    
    m_dcBack.SelectObject(OldBrush);
    m_dcBack.SelectObject(penOld);
    
    bRushBack.DeleteObject();
    penBlack.DeleteObject();
    
    
int nLenthBuf = WideCharToMultiByte(CP_ACP,0,m_strTitleInfo,-1,NULL,0,NULL,NULL) - 1;
    LONG lLeftX 
= rect.left + (rect.Width() - nLenthBuf * 6/ 2;
    LONG lLeftY 
= rect.top  + (rect.Height() - 14/ 2;
    
    m_dcBack.SetBkColor(RGB(
230,230,207));
    m_dcBack.SetTextColor(RGB(
128,128,128));
    m_dcBack.ExtTextOut(lLeftX,lLeftY,ETO_OPAQUE,NULL,m_strTitleInfo,NULL);
    
    Invalidate(FALSE);    
}


// normal
void  CMyButton::DrawBackForNor()
{    
    CRect rect;
    GetClientRect(
&rect);

    CBrush bRushBack(m_clNorBack);
    CBrush 
*OldBrush = m_dcBack.SelectObject(&bRushBack);    
    
    CPen penBlack;
    penBlack.CreatePen(PS_SOLID,
2,RGB(100,100,192));
    
    CPen 
*penOld = m_dcBack.SelectObject(&penBlack);
    
    m_dcBack.FillSolidRect(rect,RGB(
192,192,192));
    
    
//rect.DeflateRect(5,5);
//    m_dcBack.RoundRect(rect,CPoint(4,4));
    m_dcBack.FillSolidRect(rect,RGB(100,100,192));
    
    m_dcBack.SelectObject(OldBrush);
    m_dcBack.SelectObject(penOld);
    
    bRushBack.DeleteObject();
    penBlack.DeleteObject();
    
    
int nLenthBuf = WideCharToMultiByte(CP_ACP,0,m_strTitleInfo,-1,NULL,0,NULL,NULL) - 1;
    LONG lLeftX 
= rect.left + (rect.Width() - nLenthBuf * 6/ 2;
    LONG lLeftY 
= rect.top  + (rect.Height() - 14/ 2;
    
    m_dcBack.SetBkColor(m_clNorBack);
    m_dcBack.SetTextColor(m_clNorText);
    m_dcBack.ExtTextOut(lLeftX,lLeftY,ETO_OPAQUE,NULL,m_strTitleInfo,NULL);
    
    Invalidate(FALSE);
    m_bLastState 
= false;
}

 

 

void  CMyButton::OnSetFocus(CWnd *  pOldWnd) 
{
    CWnd::OnSetFocus(pOldWnd);
    
    
// TODO: Add your message handler code here
    if (!m_bLastState)
    
{
        DrawBackForFoc();
    }

}


void  CMyButton::OnKillFocus(CWnd *  pNewWnd) 
{
    CWnd::OnKillFocus(pNewWnd);
    
    
// TODO: Add your message handler code here
    if (m_bLastState)
    
{
        DrawBackForNor();
    }

}

 

void  CMyButton::OnLButtonDown(UINT nFlags, CPoint point) 
{
    
// TODO: Add your message handler code here and/or call default    
    if (m_lpDealWithBTN != NULL)
    
{
        m_lpDealWithBTN();
    }

    SetFocus();
    CWnd::OnLButtonDown(nFlags, point);
}


void  CMyButton::SetWindowText(LPCTSTR lpszString)
{
    m_strTitleInfo 
= lpszString;
    
if (m_bLastState)
    
{
        DrawBackForFoc();
    }

    
else
    
{
        DrawBackForNor();
    }

}



BOOL CMyButton::EnableWindow(BOOL bEnable 
/* = TRUE */ )
{
    
if (bEnable)
    
{
        DrawBackForNor();
    }

    
else
    
{
        DrawBackForMid();
    }


    
return CWnd::EnableWindow(bEnable);
}

注意:所有代码中ExtTextOut 完全可以用DrawText来代替,更简单一些。

为了实现主窗体跟按钮之间的通信,例如当按钮按下时,按钮要通知主窗体,我在这里添加函数指针来实现,当然也可以通过消息的方式来实现。声明函数指针:typedef void (*LPDealWithBTN)();
LPDealWithBTN m_lpDealWithBTN;//函数指针

把所有代码添加完毕就可以实现效果了。在主程序就可以添加相关的函数,如果要使用函数指针来实现通知的话,需先建立一个static函数。例如static void OnDealWithBTN01();

test:

CMyButton m_myBTN01;

m_myBTN01.CreateBTN(L"TestBTN",WS_CHILD|WS_VISIBLE,CRect(260,110,335,130),this,0,OnDealWithBTN01);

void CTestBtnDlg::OnDealWithBTN01()
{
 printf("BTN01 pressed/r/n");
}

当然也可以实现贴图,这是完全可以的。如果要贴图的话,又要实现透明效果图片的话,那么参考一下代码:

 

// 画透明图片
void  CMyButton::DrawTransParent(CBitmap  & bmp, int   const  x, int   const  y, int   const  cx, int   const  cy,
                            
int   const  srcx, int   const  srcy,CDC  * pDC,COLORREF TransparentColor)
{
    
//定义源、掩码、透明绘制环境
    CDC  SrcDC,MaskDC,TransDC;
    
//定义掩码、透明位图
    CBitmap MaskBmp,TransBmp;
    BITMAP  bm;
    
    
//创建源、掩码、透明绘制环境
    SrcDC.CreateCompatibleDC(pDC);
    MaskDC.CreateCompatibleDC(pDC);
    TransDC.CreateCompatibleDC(pDC);
    
    
//得到位图结构
    bmp.GetBitmap(&bm);
    
//创建透明位图
    TransBmp.CreateCompatibleBitmap(pDC,cx,cy);
    
//创建掩码位图
    MaskBmp.CreateBitmap(cx,cy,1,1,NULL);
    
    
//将透明位图对象选入到透明绘图环境
    CBitmap *pTransBmp = TransDC.SelectObject(&TransBmp);
    
//将目标位图绘制到透明位图中
    TransDC.BitBlt(x,y,cx,cy,pDC,srcx,srcy,SRCCOPY);
    
    
//将实际位图对象选入源绘图环境
    CBitmap *pSrcBmp = SrcDC.SelectObject(&bmp);
    
    
//设置背景为透明模式
    SrcDC.SetBkMode(TRANSPARENT);
    
//设置背景色
    if (TransparentColor)
        SrcDC.SetBkColor(TransparentColor);
    
else
    
{
        COLORREF col 
= SrcDC.GetPixel(0,bm.bmHeight-1);
        SrcDC.SetBkColor(col);
    }

    
    CBitmap 
*pMaskBmp = MaskDC.SelectObject(&MaskBmp);
    
    
//将源绘图环境绘制到掩码绘图环境中
    MaskDC.BitBlt(x,y,cx,cy,&SrcDC,0,0,SRCCOPY);
    
    
//将源位图和透明位图进行异或操作融合
    TransDC.BitBlt(x,y,cx,cy,&SrcDC,0,0,SRCINVERT);
    
//将透明位图和掩码位图进行与操作
    TransDC.BitBlt(x,y,cx,cy,&MaskDC,0,0,SRCAND);
    
//再将源位图和透明位图进行异或操作
    TransDC.BitBlt(x,y,cx,cy,&SrcDC,0,0,SRCINVERT);
    
    
//此时将透明位图绘制到目标设备上
    BOOL bRet = pDC->BitBlt(x,y,cx,cy,&TransDC,srcx,srcy,SRCCOPY);
    
    
//绘制绘图对象,并释放相应绘图环境和位图对象
    SrcDC.SelectObject(pSrcBmp);
    SrcDC.DeleteDC();
    
    TransDC.SelectObject(pTransBmp);
    TransBmp.DeleteObject();
    TransDC.DeleteDC();
    
    MaskDC.SelectObject(pMaskBmp);
    MaskDC.DeleteDC();
    MaskBmp.DeleteObject();
}

调用时:

CBitmap bmp;
bmp.LoadBitmap(IDB_BITMAP_MID);
BITMAP bm;
bmp.GetBitmap(&bm);
DrawTransParent(bmp,0,0,bm.bmWidth,bm.bmHeight,0,0,&m_dcBack,NULL);
bmp.DeleteObject(); 

 

注:原文出处http://blog.csdn.net/KevinCEC/archive/2008/01/22/2059564.aspx

你可能感兴趣的:(工作,XP,null,mfc,平台)