MFC-自绘控件(CButton篇)

示例图

MFC-自绘控件(CButton篇)_第1张图片

一、公共文件部分


头文件

#pragma once  

#include "stdafx.h"  
#include   
#include "gdiplus.h"  
#pragma comment( lib, "gdiplus.lib" )  
using namespace Gdiplus;
//按钮的状态  
enum
{
	CTRL_NOFOCUS = 0x01,            //普通  
	CTRL_FOCUS,                     //mousemove  
	CTRL_SELECTED,                  //buttondown  
	CTRL_DISABLE,                   //无效  
};

//图片形式  
enum
{
	BTN_IMG_1 = 1,                  //  
	BTN_IMG_3 = 3,                  //3分图(1个图片内有3小图,下同)  
	BTN_IMG_4 = 4,                  //4分图  
};

//按钮类型  
enum
{
	BTN_TYPE_NORMAL = 0x10,         //普通BTN  
	BTN_TYPE_MENU,                  //菜单类型的BTN  
	BTN_TYPE_STATIC,                //静态类型的BTN  
};

//从资源里面加载位图  
bool LoadImageFromResourse(CImage* pImg, UINT nImgID, LPCTSTR lpImgType);
bool LoadPicture(CImage& bmp, UINT nImgID, LPCTSTR lpImgType = _T("PNG"));          //含Alpha通道的图片处理成CImage

源码cpp

#include "stdafx.h"  
#include "Public.h"  


bool LoadImageFromResourse(CImage* pImg, UINT nImgID, LPCTSTR lpImgType)
{
	if (pImg == NULL)
	{
		return FALSE;
	}
	pImg->Destroy();

	//查找资源  
	HRSRC hRsrc = ::FindResource(AfxGetResourceHandle(), MAKEINTRESOURCE(nImgID), lpImgType);
	if (hRsrc == NULL)
	{
		return false;
	}

	//加载资源  
	HGLOBAL hImgData = ::LoadResource(AfxGetResourceHandle(), hRsrc);
	if (hImgData == NULL)
	{
		::FreeResource(hImgData);
		return false;
	}


	LPVOID lpVoid = ::LockResource(hImgData);                           //锁定内存中指定资源  
	LPSTREAM pStream = NULL;
	DWORD dwSize = ::SizeofResource(AfxGetResourceHandle(), hRsrc);
	HGLOBAL hNew = ::GlobalAlloc(GHND, dwSize);
	LPBYTE lpByte = (LPBYTE)::GlobalLock(hNew);
	::memcpy(lpByte, lpVoid, dwSize);
	::GlobalUnlock(hNew);                                              //解除资源锁定  

	HRESULT ht = ::CreateStreamOnHGlobal(hNew, TRUE, &pStream);
	if (ht != S_OK)
	{
		GlobalFree(hNew);
	}
	else
	{
		//加载图片  
		pImg->Load(pStream);
		GlobalFree(hNew);
	}

	//释放资源  
	::FreeResource(hImgData);
	return true;
}

bool LoadPicture(CImage& bmp, UINT nImgID, LPCTSTR lpImgType)           //含Alpha通道的图片处理成CImage  
{
	LoadImageFromResourse(&bmp, nImgID, lpImgType);                 //加载图片资源  

	if (bmp.IsNull())
	{
		return false;
	}
	if (bmp.GetBPP() == 32)                                              //确认该图片包含Alpha通道  
	{
		for (int i = 0; i < bmp.GetWidth(); i++)
		{
			for (int j = 0; j < bmp.GetHeight(); j++)
			{
				byte* pByte = (byte*)bmp.GetPixelAddress(i, j);
				pByte[0] = pByte[0] * pByte[3] / 255;
				pByte[1] = pByte[1] * pByte[3] / 255;
				pByte[2] = pByte[2] * pByte[3] / 255;
			}
		}
	}

	return true;
}

二、按钮

头文件

#pragma once  
#include "Public.h"
//////////////////////////////////////////////////////////////////////////

#define DEF_TEXT_FRAME_COLOR			RGB(255,255,255)				//默认颜色
#define DEF_TEXT_COLOR					RGB(10,10,10)					//默认颜色
#define TOOLTIP_ID						100								//提示 ID

//////////////////////////////////////////////////////////////////////////
class CPngButton : public CButton
{
public:
	CPngButton();
	virtual ~CPngButton();
public:
	// 初始化
	void Init(UINT nImg, int nPartNum, UINT nBtnType = BTN_TYPE_NORMAL);
	//设置颜色
	bool SetTextColor(COLORREF crTextColor, COLORREF crTextFrameColor = DEF_TEXT_FRAME_COLOR, bool bShowFrame = false);
	//设置提示
	void SetToolTips(LPCTSTR pszTips);
	//设置鼠标形状
	void SetCursorType(HCURSOR hCursor);
	//设置字体大小及类型
	void SetFontType(int fontSize, CString fontType);
protected:
	afx_msg BOOL OnEraseBkgnd(CDC* pDC);
	afx_msg void OnMouseMove(UINT nFlags, CPoint point);
	afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
	afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
	afx_msg LRESULT OnMouseHOver(WPARAM wParam, LPARAM lParam);
	afx_msg LRESULT OnMouseLeave(WPARAM wParam, LPARAM lParam);
	afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
	afx_msg void OnPaint();
	DECLARE_MESSAGE_MAP()

protected:
	virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
	virtual void PreSubclassWindow();
	virtual BOOL PreTranslateMessage(MSG * pMsg);
	bool ShowImage(CDC* pDC, Image* pImage, UINT nState);
	void PaintParent();
	Image *ImageFromResource(HINSTANCE hInstance, UINT uImgID, LPCTSTR lpType);
	void UpdateToolTip();
	void DrawTextString(CDC * pDC, LPCTSTR pszString, COLORREF crText, COLORREF crFrame, LPRECT lpRect);
	void DrawTextString(CDC * pDC, LPCTSTR pszString, COLORREF crText, COLORREF crFrame, int nXPos, int nYPos);

private:
	int m_nImgPart;									//载入的图片是几块
	UINT			m_nState;						//控件状态
	UINT			m_nBtnType;						//按钮类型
	BOOL			m_bMenuOn;						//是否按下
	BOOL			m_bTracked;						//是否移动
	BOOL			m_bShowTextFrame;				//是否显示艺术字体
	COLORREF		m_crTextColor;					//字体颜色
	COLORREF		m_crTextFrameColor;				//艺术字体边缘颜色
	CString			m_strTips;						//提示
	HCURSOR			m_cursor;						//光标
	CToolTipCtrl	m_ToolTip;						//提示控件
	Image*			m_pImage;						//背景图片
	CFont			m_font;							//字体
};

源码cpp

// PngButton.cpp : implementation file  

#include "stdafx.h"  
#include "PngButton.h"  

CPngButton::CPngButton()
{
	m_bTracked	= FALSE;
	m_bMenuOn	= FALSE;
	m_nImgPart	= 0;
	m_pImage	= NULL;
	m_nState			= CTRL_NOFOCUS;
	m_nBtnType			= BTN_TYPE_NORMAL;
	m_bShowTextFrame	= FALSE;
	m_crTextColor		= DEF_TEXT_COLOR;
	m_crTextFrameColor	= DEF_TEXT_FRAME_COLOR;
	m_cursor = ::LoadCursor(NULL, IDC_ARROW);
}

CPngButton::~CPngButton()
{
	if (m_pImage != NULL)
	{
		delete m_pImage;
		m_pImage = NULL;
	}
}

void CPngButton::Init(UINT nImg, int nPartNum, UINT nBtnType)
{
	m_pImage = ImageFromResource(AfxGetResourceHandle(), nImg, L"PNG");
	m_nBtnType = nBtnType;
	m_nImgPart = nPartNum;

	if (m_pImage == NULL)
		return;

	CRect rcButton;

	if (m_nImgPart == BTN_IMG_1)
		rcButton = CRect(0, 0, m_pImage->GetWidth(), m_pImage->GetHeight());
	else if (m_nImgPart == BTN_IMG_3)
		rcButton = CRect(0, 0, m_pImage->GetWidth() / 3, m_pImage->GetHeight());
	else if (m_nImgPart == BTN_IMG_4)
		rcButton = CRect(0, 0, m_pImage->GetWidth() / 4, m_pImage->GetHeight());
	else
		return;

	SetWindowPos(NULL, 0, 0, rcButton.Width(), rcButton.Height(), SWP_NOACTIVATE | SWP_NOMOVE);
}

BEGIN_MESSAGE_MAP(CPngButton, CButton)
	//{{AFX_MSG_MAP(CPngButton)  
	ON_WM_ERASEBKGND()
	ON_WM_MOUSEMOVE()
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	ON_WM_PAINT()
	ON_MESSAGE(WM_MOUSEHOVER, OnMouseHOver)
	ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave)
	//}}AFX_MSG_MAP  
	ON_WM_SETCURSOR()
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////  
// CPngButton message handlers  

void CPngButton::OnPaint()
{
	CButton::OnPaint();
}

void CPngButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
	if (!IsWindowEnabled())
		m_nState = CTRL_DISABLE;
	CDC dc;
	dc.Attach(lpDrawItemStruct->hDC);
	ShowImage(&dc, m_pImage, m_nState);
	dc.Detach();
}

bool CPngButton::ShowImage(CDC* pDC, Image* pImage, UINT nState)
{
	bool bSuc = false;

	if (pImage != NULL)
	{
		CRect rcButton;
		if (m_nImgPart == BTN_IMG_1)
			rcButton = CRect(0, 0, m_pImage->GetWidth(), m_pImage->GetHeight());
		else if (m_nImgPart == BTN_IMG_3)
		{
			if (nState == CTRL_NOFOCUS)
				rcButton = CRect(0, 0, m_pImage->GetWidth() / 3, m_pImage->GetHeight());
			else if (nState == CTRL_FOCUS)
				rcButton = CRect(m_pImage->GetWidth() / 3, 0, m_pImage->GetWidth() / 3 * 2, m_pImage->GetHeight());
			else if (nState == CTRL_SELECTED)
				rcButton = CRect(m_pImage->GetWidth() / 3 * 2, 0, m_pImage->GetWidth(), m_pImage->GetHeight());
			else
				return false;
		}
		else if (m_nImgPart == BTN_IMG_4)
		{
			if (nState == CTRL_NOFOCUS)
				rcButton = CRect(0, 0, m_pImage->GetWidth() / 4, m_pImage->GetHeight());
			else if (nState == CTRL_FOCUS)
				rcButton = CRect(m_pImage->GetWidth() / 4, 0, m_pImage->GetWidth() / 4 * 2, m_pImage->GetHeight());
			else if (nState == CTRL_SELECTED)
				rcButton = CRect(m_pImage->GetWidth() / 4 * 2, 0, m_pImage->GetWidth() / 4 * 3, m_pImage->GetHeight());
			else if (nState == CTRL_DISABLE)
				rcButton = CRect(m_pImage->GetWidth() / 4 * 3, 0, m_pImage->GetWidth(), m_pImage->GetHeight());
			else
				return false;
		}
		else
			return false;
		pDC->SetBkMode(TRANSPARENT);
		Graphics graph(pDC->GetSafeHdc());
		graph.DrawImage(pImage, RectF(0,0, rcButton.Width(), rcButton.Height()), rcButton.left, rcButton.top, rcButton.Width(), rcButton.Height(), UnitPixel);
		graph.ReleaseHDC(pDC->GetSafeHdc());
		//绘画字体
		CString szText;
		GetWindowText(szText);
		CRect txtRc = { 0,0,rcButton.Width() ,rcButton.Height() };
		CFont* oldFont = pDC->SelectObject(m_font.GetSafeHandle() ? &m_font : GetFont());
		if (!m_bShowTextFrame)
		{
			pDC->SetTextColor(m_crTextColor);
			pDC->DrawText(szText, szText.GetLength(), &txtRc, DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_TABSTOP);
		}
		else
		{
			//艺术字体
			DrawTextString(pDC, szText, m_crTextColor, m_crTextFrameColor, &txtRc);
		}
		pDC->SelectObject(oldFont);
		bSuc = true;
	}
	return bSuc;
}

Image *CPngButton::ImageFromResource(HINSTANCE hInstance, UINT uImgID, LPCTSTR lpType)
{
	HRSRC hResInfo = ::FindResource(hInstance, MAKEINTRESOURCE(uImgID), lpType);
	if (hResInfo == NULL)
		return NULL; //fail  
	DWORD dwSize;
	dwSize = SizeofResource(hInstance, hResInfo); //get resource size(bytes)   
	HGLOBAL hResData;
	hResData = ::LoadResource(hInstance, hResInfo);
	if (hResData == NULL)
		return NULL; //fail  
	HGLOBAL hMem;
	hMem = ::GlobalAlloc(GMEM_MOVEABLE, dwSize);
	if (hMem == NULL) {
		::FreeResource(hResData);
		return NULL;
	}
	LPVOID lpResData, lpMem;
	lpResData = ::LockResource(hResData);
	lpMem = ::GlobalLock(hMem);
	::CopyMemory(lpMem, lpResData, dwSize); //copy memory  
	::GlobalUnlock(hMem);
	::FreeResource(hResData); //free memory  

	IStream *pStream;
	HRESULT hr;
	hr = ::CreateStreamOnHGlobal(hMem, TRUE, &pStream);//create stream object  
	Image *pImage = NULL;
	if (SUCCEEDED(hr)) {
		pImage = Image::FromStream(pStream);//get GDI+ pointer  
		pStream->Release();
	}
	::GlobalFree(hMem);
	return pImage;
}

void CPngButton::PreSubclassWindow()
{
	ModifyStyle(0, BS_OWNERDRAW);

	if (NULL != GetSafeHwnd())
	{
		if (!(GetButtonStyle() & WS_CLIPSIBLINGS))
			SetWindowLong(GetSafeHwnd(), GWL_STYLE, GetWindowLong(GetSafeHwnd(),
				GWL_STYLE) | WS_CLIPSIBLINGS);
	}

	CButton::PreSubclassWindow();
}
//消息解释
BOOL CPngButton::PreTranslateMessage(MSG * pMsg)
{
	if (m_ToolTip.m_hWnd != NULL)
		m_ToolTip.RelayEvent(pMsg);
	return CButton::PreTranslateMessage(pMsg);
}
//设置提示
void CPngButton::SetToolTips(LPCTSTR pszTips)
{
	m_strTips = pszTips;
	UpdateToolTip();
}

//更新提示
void CPngButton::UpdateToolTip()
{
	if (GetSafeHwnd())
	{
		if (m_ToolTip.GetSafeHwnd() == NULL) m_ToolTip.Create(this);
		if (m_strTips.IsEmpty() == false)
		{
			CRect ClientRect;
			GetClientRect(&ClientRect);
			m_ToolTip.Activate(TRUE);
			m_ToolTip.AddTool(this, m_strTips, &ClientRect, TOOLTIP_ID);
		}
		else m_ToolTip.Activate(FALSE);
	}
	return;
}
//设置颜色
bool CPngButton::SetTextColor(COLORREF crTextColor, COLORREF crTextFrameColor, bool bShowFrame)
{
	m_crTextColor = crTextColor;
	m_bShowTextFrame = bShowFrame;
	m_crTextFrameColor = crTextFrameColor;

	if (GetSafeHwnd()) Invalidate(FALSE);
	return true;
}
void CPngButton::SetCursorType(HCURSOR hCursor) {
	m_cursor = hCursor;
}
//光标消息
BOOL CPngButton::OnSetCursor(CWnd * pWnd, UINT nHitTest, UINT message)
{
	::SetCursor(m_cursor);
	return TRUE;
}
void CPngButton::SetFontType(int fontSize, CString fontType) {
	LOGFONT lf;
	memset(&lf, 0, sizeof(LOGFONT));
	lf.lfHeight = fontSize;
	_tcsncpy_s(lf.lfFaceName, LF_FACESIZE,fontType, fontType.GetLength());
	VERIFY(m_font.CreateFontIndirect(&lf));
}
BOOL CPngButton::OnEraseBkgnd(CDC* pDC)
{
	return TRUE;
}

void CPngButton::OnMouseMove(UINT nFlags, CPoint point)
{
	// TODO: Add your message handler code here and/or call default  
	if (!m_bTracked) {
		TRACKMOUSEEVENT tme;
		ZeroMemory(&tme, sizeof(TRACKMOUSEEVENT));
		tme.cbSize = sizeof(TRACKMOUSEEVENT);
		tme.dwFlags = TME_HOVER | TME_LEAVE;
		tme.dwHoverTime = 1;
		tme.hwndTrack = this->GetSafeHwnd();
		if (::_TrackMouseEvent(&tme))
			m_bTracked = TRUE;
	}

	CButton::OnMouseMove(nFlags, point);
}

void CPngButton::OnLButtonDown(UINT nFlags, CPoint point)
{
	if (m_nState != CTRL_SELECTED)
	{
		m_nState = CTRL_SELECTED;

		if (!m_bMenuOn)
			m_bMenuOn = TRUE;

		PaintParent();
	}

	CButton::OnLButtonDown(nFlags, point);
}

void CPngButton::OnLButtonUp(UINT nFlags, CPoint point)
{
	if (m_nState != CTRL_FOCUS)
	{
		m_nState = CTRL_FOCUS;
		PaintParent();
	}

	CButton::OnLButtonUp(nFlags, point);
}

LRESULT CPngButton::OnMouseHOver(WPARAM wParam, LPARAM lParam)
{
	//鼠标放上去时  
	if (m_nState != CTRL_FOCUS)
	{
		m_nState = CTRL_FOCUS;
		PaintParent();
	}

	return 0;
}
LRESULT CPngButton::OnMouseLeave(WPARAM wParam, LPARAM lParam)
{
	//鼠标移开时  
	m_bTracked = FALSE;

	if (m_nBtnType == BTN_TYPE_NORMAL)
		m_nState = CTRL_NOFOCUS;
	else if (m_nBtnType == BTN_TYPE_MENU)
	{
		if (m_bMenuOn)
			m_nState = CTRL_SELECTED;
		else
			m_nState = CTRL_NOFOCUS;
	}

	PaintParent();
	return 0;
}

void CPngButton::PaintParent()
{
	CRect   rect;
	GetWindowRect(&rect);
	GetParent()->ScreenToClient(&rect);
	GetParent()->InvalidateRect(&rect);
}

//艺术字体
void CPngButton::DrawTextString(CDC * pDC, LPCTSTR pszString, COLORREF crText, COLORREF crFrame, LPRECT lpRect)
{
	//变量定义
	int nStringLength = lstrlen(pszString);
	int nXExcursion[8] = { 1,1,1,0,-1,-1,-1,0 };
	int nYExcursion[8] = { -1,0,1,1,1,0,-1,-1 };
	//绘画边框
	pDC->SetTextColor(crFrame);
	CRect rcDraw;
	for (int i = 0; i < sizeof(nXExcursion)/sizeof(nXExcursion[0]); ++i)
	{
		rcDraw.CopyRect(lpRect);
		rcDraw.OffsetRect(nXExcursion[i], nYExcursion[i]);
		pDC->DrawText(pszString, nStringLength, &rcDraw, DT_VCENTER | DT_CENTER | DT_SINGLELINE | DT_END_ELLIPSIS);
	}
	//绘画字体
	rcDraw.CopyRect(lpRect);
	pDC->SetTextColor(crText);
	pDC->DrawText(pszString, nStringLength, &rcDraw, DT_VCENTER | DT_CENTER | DT_SINGLELINE | DT_END_ELLIPSIS);
	return;
}

//艺术字体
void CPngButton::DrawTextString(CDC * pDC, LPCTSTR pszString, COLORREF crText, COLORREF crFrame, int nXPos, int nYPos)
{
	//变量定义
	int nStringLength = lstrlen(pszString);
	int nXExcursion[8] = { 1,1,1,0,-1,-1,-1,0 };
	int nYExcursion[8] = { -1,0,1,1,1,0,-1,-1 };
	//绘画边框
	pDC->SetTextColor(crFrame);
	for (int i = 0; i < sizeof(nXExcursion) / sizeof(nXExcursion[0]); i++)
	{
		pDC->TextOut(nXPos + nXExcursion[i], nYPos + nYExcursion[i], pszString, nStringLength);
	}

	//绘画字体
	pDC->SetTextColor(crText);
	pDC->TextOut(nXPos, nYPos, pszString, nStringLength);
	return;
}


你可能感兴趣的:(CC++)