按钮重绘支持PNG图片作为背景很使用。可以实现按钮一种背景图片,然后鼠标点击按钮,增加一个透明的png边框,也可以修改以下实现鼠标停留在某个按钮上面,改变按钮的状态。
#if !defined(AFX_PICBUTTON_H__4A8AEB90_4455_44B5_B4BE_20B5B77453E1__INCLUDED_)
#define AFX_PICBUTTON_H__4A8AEB90_4455_44B5_B4BE_20B5B77453E1__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// PicButton.h : header file
//
#define ALIGN_HORZ 0
#define ALIGN_VERT 1
/////////////////////////////////////////////////////////////////////////////
// CPicButton window
class CPicButton : public CButton
{
// Construction
public:
CPicButton();
// Attributes
public:
// Operations
public:
void SetTextColor(COLORREF color) { m_TextColor=color; }
void SetBkColor(COLORREF color) { m_BackColor=color; }
void SetFocusColor(COLORREF color) { m_FocusColor=color; }
void SetBitmapEx(LPCTSTR lpszFile);
void SetBitmapEx(UINT nBitmapID);
void SetBorder(UINT nSet){m_nBorder=nSet;}
void SetTextAlign(UINT nSet){m_nTextAlign=nSet;}
void SetIconAlign(UINT nSet){m_nIconAlign=nSet;}
void SetBackBmp(LPCTSTR lpszFile);
void SetBackBmp(UINT nNormalID);
void SetBitmap(UINT nNormalID,UINT nDisableID=0);
void SetBitmap(LPCTSTR lpszNormal,LPCTSTR lpszDisabled=NULL);
void SetCheck(int nCheck, BOOL bRepaint = TRUE);
void SetStatic(BOOL bSet){m_bStatic=bSet;}
int GetCheck();
void DeleteObject();
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CPicButton)
public:
virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
protected:
virtual void PreSubclassWindow();
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~CPicButton();
// Generated message map functions
protected:
//{{AFX_MSG(CPicButton)
afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
afx_msg BOOL OnClicked();
afx_msg void OnCaptureChanged(CWnd *pWnd);
afx_msg void OnKillFocus(CWnd* pNewWnd);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
//}}AFX_MSG
LRESULT OnSetCheck(WPARAM wParam, LPARAM lParam);
LRESULT OnGetCheck(WPARAM wParam, LPARAM lParam);
DECLARE_MESSAGE_MAP()
private:
COLORREF m_TextColor, m_BackColor,m_FocusColor;
HBITMAP m_bmpNormal,m_bmpDisabled;
CBitmap m_bmpBack,m_bmpButton;
UINT m_nBorder;
UINT m_nTextAlign,m_nIconAlign;
int m_nCheck,m_bCheckBox;
BOOL m_MouseOnButton,m_bStatic;
};
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_PICBUTTON_H__4A8AEB90_4455_44B5_B4BE_20B5B77453E1__INCLUDED_)
实现
// PicButton.cpp : implementation file
//
#include "stdafx.h"
#include "PicButton.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CPicButton
CPicButton::CPicButton()
{
m_TextColor=RGB(255,255,255);
m_BackColor=RGB(40,40,70);
m_FocusColor=RGB(255,0,0);
m_nBorder=BF_RECT;
m_nTextAlign=DT_CENTER;
m_nIconAlign=ALIGN_HORZ;
m_bmpNormal=NULL;
m_bmpDisabled=NULL;
m_nCheck=0;
m_bCheckBox=0;
m_MouseOnButton=FALSE;
m_bStatic = 0;
}
CPicButton::~CPicButton()
{
DeleteObject();
}
BEGIN_MESSAGE_MAP(CPicButton, CButton)
//{{AFX_MSG_MAP(CPicButton)
ON_WM_CTLCOLOR()
ON_WM_ERASEBKGND()
ON_CONTROL_REFLECT_EX(BN_CLICKED, OnClicked)
ON_WM_CAPTURECHANGED()
ON_WM_KILLFOCUS()
ON_WM_MOUSEMOVE()
//}}AFX_MSG_MAP
ON_MESSAGE(BM_SETCHECK, OnSetCheck)
ON_MESSAGE(BM_GETCHECK, OnGetCheck)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CPicButton message handlers
void CPicButton::DeleteObject()
{
if(m_bmpNormal){
::DeleteObject(m_bmpNormal);
m_bmpNormal=NULL;
}
if(m_bmpDisabled){
::DeleteObject(m_bmpDisabled);
m_bmpDisabled=NULL;
}
if(m_bmpButton.GetSafeHandle()){
m_bmpButton.DeleteObject();
}
if(m_bmpBack.GetSafeHandle()){
m_bmpBack.DeleteObject();
}
}
void CPicButton::SetBitmap(UINT nNormalID,UINT nDisableID)
{
HINSTANCE hInstResource=AfxFindResourceHandle(MAKEINTRESOURCE(nNormalID), RT_BITMAP);
m_bmpNormal=(HBITMAP)::LoadImage(hInstResource, MAKEINTRESOURCE(nNormalID), IMAGE_BITMAP, 0, 0, 0);
if(nDisableID)
m_bmpDisabled=(HBITMAP)::LoadImage(hInstResource, MAKEINTRESOURCE(nDisableID), IMAGE_BITMAP, 0, 0, 0);
else
m_bmpDisabled=(HBITMAP)::LoadImage(hInstResource, MAKEINTRESOURCE(nNormalID), IMAGE_BITMAP, 0, 0, 0);
}
void CPicButton::SetBitmap(LPCTSTR lpszNormal,LPCTSTR lpszDisabled)
{
m_bmpNormal=(HBITMAP)::LoadImage(NULL, lpszNormal, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
if(lpszDisabled)
m_bmpDisabled=(HBITMAP)::LoadImage(NULL, lpszDisabled, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
else
m_bmpDisabled=NULL;
}
void CPicButton::SetBitmapEx(LPCTSTR lpszFile)
{
if(lpszFile==NULL){
m_bmpButton.DeleteObject();
}
else{
if(!m_bmpButton.GetSafeHandle())m_bmpButton.DeleteObject();
m_bmpButton.LoadBitmap(lpszFile);
}
}
void CPicButton::SetBitmapEx(UINT nBitmapID)
{
if(nBitmapID==0){
m_bmpButton.DeleteObject();
}
else{
if(!m_bmpButton.GetSafeHandle())m_bmpButton.DeleteObject();
m_bmpButton.LoadBitmap(nBitmapID);
}
}
void CPicButton::SetBackBmp(LPCTSTR lpszFile)
{
if(lpszFile==NULL){
m_bmpBack.DeleteObject();
}
else{
if(!m_bmpBack.GetSafeHandle())m_bmpBack.DeleteObject();
m_bmpBack.LoadBitmap(lpszFile);
}
}
void CPicButton::SetBackBmp(UINT nNormalID)
{
if(nNormalID==0){
m_bmpBack.DeleteObject();
}
else{
if(!m_bmpBack.GetSafeHandle())m_bmpBack.DeleteObject();
m_bmpBack.LoadBitmap(nNormalID);
}
}
void TransparentBlt2(HDC hdcDest, // 目标DC
int nXOriginDest, // 目标X偏移
int nYOriginDest, // 目标Y偏移
int nWidthDest, // 目标宽度
int nHeightDest, // 目标高度
HDC hdcSrc, // 源DC
int nXOriginSrc, // 源X起点
int nYOriginSrc, // 源Y起点
int nWidthSrc, // 源宽度
int nHeightSrc, // 源高度
UINT crTransparent // 透明色,COLORREF类型
)
{
HBITMAP hOldImageBMP, hImageBMP = CreateCompatibleBitmap(hdcDest, nWidthDest, nHeightDest); // 创建兼容位图
HBITMAP hOldMaskBMP, hMaskBMP = CreateBitmap(nWidthDest, nHeightDest, 1, 1, NULL); // 创建单色掩码位图
HDC hImageDC = CreateCompatibleDC(hdcDest);
HDC hMaskDC = CreateCompatibleDC(hdcDest);
hOldImageBMP = (HBITMAP)SelectObject(hImageDC, hImageBMP);
hOldMaskBMP = (HBITMAP)SelectObject(hMaskDC, hMaskBMP);
// 将源DC中的位图拷贝到临时DC中
if (nWidthDest == nWidthSrc && nHeightDest == nHeightSrc)
BitBlt(hImageDC, 0, 0, nWidthDest, nHeightDest, hdcSrc, nXOriginSrc, nYOriginSrc, SRCCOPY);
else
StretchBlt(hImageDC, 0, 0, nWidthDest, nHeightDest,
hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc, SRCCOPY);
// 设置透明色
SetBkColor(hImageDC, crTransparent);
// 生成透明区域为白色,其它区域为黑色的掩码位图
BitBlt(hMaskDC, 0, 0, nWidthDest, nHeightDest, hImageDC, 0, 0, SRCCOPY);
// 生成透明区域为黑色,其它区域保持不变的位图
SetBkColor(hImageDC, RGB(0,0,0));
SetTextColor(hImageDC, RGB(255,255,255));
BitBlt(hImageDC, 0, 0, nWidthDest, nHeightDest, hMaskDC, 0, 0, SRCAND);
// 透明部分保持屏幕不变,其它部分变成黑色
SetBkColor(hdcDest,RGB(0xff,0xff,0xff));
SetTextColor(hdcDest,RGB(0,0,0));
BitBlt(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, hMaskDC, 0, 0, SRCAND);
// "或"运算,生成最终效果
BitBlt(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, hImageDC, 0, 0, SRCPAINT);
SelectObject(hImageDC, hOldImageBMP);
DeleteDC(hImageDC);
SelectObject(hMaskDC, hOldMaskBMP);
DeleteDC(hMaskDC);
DeleteObject(hImageBMP);
DeleteObject(hMaskBMP);
}
void DrawTransparent(CDC *pDC,int x,int y,HBITMAP hBitmap)
{
CDC memDC;
memDC.CreateCompatibleDC(pDC);
CBitmap *pOldBitmap=memDC.SelectObject(CBitmap::FromHandle(hBitmap));
BITMAP bm;
::GetObject(hBitmap,sizeof(BITMAP),&bm);
COLORREF crTransparent=memDC.GetPixel(0,0);
TransparentBlt2(pDC->m_hDC,x,y,bm.bmWidth,bm.bmHeight,memDC.m_hDC,0,0,bm.bmWidth,bm.bmHeight,crTransparent);
if(pOldBitmap)memDC.SelectObject(pOldBitmap);
}
void DrawTransparent(CDC *pDC,int x,int y,HBITMAP hBitmap,int nIndex)
{
CDC memDC;
memDC.CreateCompatibleDC(pDC);
CBitmap *pOldBitmap=memDC.SelectObject(CBitmap::FromHandle(hBitmap));
BITMAP bm;
::GetObject(hBitmap,sizeof(BITMAP),&bm);
COLORREF crTransparent;
int n = bm.bmHeight;
if( n != 20 )
crTransparent=memDC.GetPixel(0,0);
else
crTransparent=RGB(0,0,0);
TransparentBlt2(pDC->m_hDC,x,y,bm.bmWidth/4-10,bm.bmHeight-5,memDC.m_hDC,nIndex*bm.bmWidth/4,0,bm.bmWidth/4,bm.bmHeight,crTransparent);
if(pOldBitmap)memDC.SelectObject(pOldBitmap);
}
void CPicButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
CRect rcItem=lpDrawItemStruct->rcItem;
CDC *pDC=CDC::FromHandle(lpDrawItemStruct->hDC);
BOOL bFocus=lpDrawItemStruct->itemState&ODS_FOCUS;
BOOL bSelected=lpDrawItemStruct->itemState&ODS_SELECTED;
BOOL bDisabled=lpDrawItemStruct->itemState&ODS_DISABLED;
CString strCaption;
GetWindowText(strCaption);
if(m_bCheckBox||m_bmpBack.GetSafeHandle()==NULL)
pDC->FillSolidRect(&rcItem,m_BackColor);///////设置按钮背景色
else if(m_bmpBack.GetSafeHandle())
DrawTransparent(pDC,0,0,(HBITMAP)m_bmpBack,bDisabled?3:(bSelected?2:(bFocus?1:0)));
if(m_bmpNormal)
{
BITMAP bm;
::GetObject(m_bmpNormal,sizeof(BITMAP),&bm);
if(strCaption.IsEmpty())
{
DrawTransparent(pDC,
(rcItem.Width()-bm.bmWidth)/2,
(rcItem.Height()-bm.bmHeight)/2,
bDisabled?m_bmpDisabled:m_bmpNormal);
}
else
{
if(m_nIconAlign==ALIGN_HORZ)
{
DrawTransparent(pDC,
2,
(rcItem.Height()-bm.bmHeight)/2,
bDisabled?m_bmpDisabled:m_bmpNormal);
rcItem.left+=2+bm.bmWidth+2;
}
if(m_nIconAlign==ALIGN_VERT)
{
DrawTransparent(pDC,
(rcItem.Width()-bm.bmWidth)/2,
0,
bDisabled?m_bmpDisabled:m_bmpNormal);
rcItem.top+=0+bm.bmHeight+0;
}
}
}
if(m_bmpButton.GetSafeHandle())
{
BITMAP bm;
m_bmpButton.GetBitmap(&bm);
bm.bmWidth/=4;
if(strCaption.IsEmpty())
{
DrawTransparent(pDC,
(rcItem.Width()-bm.bmWidth)/2,
(rcItem.Height()-bm.bmHeight)/2,
(HBITMAP)m_bmpButton,
m_bCheckBox?(m_nCheck?0:1):(bDisabled?3:(bSelected?2:(bFocus?1:0)))
);
}
else
{
if(m_nIconAlign==ALIGN_HORZ)
{
if(GetExStyle()&WS_EX_RIGHT)
{
DrawTransparent(pDC,
rcItem.right-bm.bmWidth+3,
(rcItem.Height()-bm.bmHeight)/2,
(HBITMAP)m_bmpButton,
m_bCheckBox?(m_nCheck?0:1):(bDisabled?3:(bSelected?2:(bFocus?1:0)))
);
rcItem.right-=(2+bm.bmWidth+2);
}
else
{
DrawTransparent(pDC,
2,
(rcItem.Height()-bm.bmHeight)/2,
(HBITMAP)m_bmpButton,
m_bCheckBox?(m_nCheck?0:1):(bDisabled?3:(bSelected?2:(bFocus?1:0)))
);
rcItem.left+=2+bm.bmWidth+2;
}
}
if(m_nIconAlign==ALIGN_VERT)
{
DrawTransparent(pDC,
(rcItem.Width()-bm.bmWidth)/2+(bSelected?1:0),
0,
(HBITMAP)m_bmpButton,
m_bCheckBox?(m_nCheck?0:1):(bDisabled?3:(bSelected?2:(bFocus?1:0))));
rcItem.top+=0+bm.bmHeight+0;
}
}
}
if(!strCaption.IsEmpty())
{
if(rcItem.left==0)rcItem.left=2;
pDC->SetTextColor(m_TextColor);
if(bDisabled)pDC->SetTextColor(RGB(192,192,192));
if(!m_bCheckBox)
if(bFocus)pDC->SetTextColor(m_FocusColor);//////设置按钮获得焦点时的颜色
pDC->SetBkMode(TRANSPARENT);
pDC->DrawText(strCaption,&rcItem,m_nTextAlign|DT_VCENTER|DT_SINGLELINE);
pDC->SetBkMode(OPAQUE);
}
}
void CPicButton::PreSubclassWindow()
{
if(GetButtonStyle()&BS_CHECKBOX)
m_bCheckBox=1;
ModifyStyle(0,BS_OWNERDRAW);
CButton::PreSubclassWindow();
}
HBRUSH CPicButton::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
return (HBRUSH)::GetStockObject(NULL_BRUSH);
}
BOOL CPicButton::OnEraseBkgnd(CDC* pDC)
{
return TRUE;
}
LRESULT CPicButton::OnSetCheck(WPARAM wParam, LPARAM lParam)
{
switch (wParam)
{
case BST_CHECKED:
case BST_INDETERMINATE:
SetCheck(1);
break;
default:
SetCheck(0);
break;
}
return 0;
}
LRESULT CPicButton::OnGetCheck(WPARAM wParam, LPARAM lParam)
{
return GetCheck();
}
void CPicButton::SetCheck(int nCheck, BOOL bRepaint)
{
if (nCheck == 0)
m_nCheck = 0;
else
m_nCheck = 1;
if (bRepaint) Invalidate();
}
int CPicButton::GetCheck()
{
return m_nCheck;
}
BOOL CPicButton::OnClicked()
{
m_nCheck = !m_nCheck;
if(m_bCheckBox)Invalidate();
return FALSE;
}
void CPicButton::OnMouseMove(UINT nFlags, CPoint point)
{
CWnd* pWnd;
CWnd* pParent;
CButton::OnMouseMove(nFlags, point);
if (nFlags & MK_LBUTTON && m_MouseOnButton == FALSE) return;
pWnd = GetActiveWindow();
pParent = GetOwner();
if ((GetCapture() != this) && (pWnd != NULL && pParent != NULL))
{
m_MouseOnButton = TRUE;
SetFocus();
SetCapture();
Invalidate();
}
else
{
CRect rc;
GetClientRect(&rc);
if(!rc.PtInRect(point)){
if(m_MouseOnButton == TRUE){
m_MouseOnButton = FALSE;
Invalidate();
}
if(!(nFlags & MK_LBUTTON)) ReleaseCapture();
}
}
}
void CPicButton::OnKillFocus(CWnd * pNewWnd)
{
CButton::OnKillFocus(pNewWnd);
if(m_MouseOnButton == TRUE){
m_MouseOnButton = FALSE;
Invalidate();
}
}
void CPicButton::OnCaptureChanged(CWnd *pWnd)
{
if (m_MouseOnButton == TRUE){
ReleaseCapture();
Invalidate();
}
CButton::OnCaptureChanged(pWnd);
}