自绘Tab控件

自绘tab按钮效果图如下:

 

使用例子:

MyTabControl *tabControl = NULL;

tabControl = new MyTabControl();
tabControl->Create(this, CRect(0,0,125,27), L"花生", ID_BTN_MYTAB);
tabControl->SetTabIndex(index);

tabControl->SetShowText(L"花生");

tabControl->SetTabState(TAB_STATE_DOWN);

tabControl->SetToolTipText(L"花生");

头文件:

#pragma once
#include "LhsButton.h"

// MyTabControl

#define ID_BTN_MYTAB_CLOSE	2100			//关闭按钮的id
#define MYWM_BTN_TAB_CLOSE WM_USER+2001		//关闭按钮单击响应
#define MYWM_BTN_TAB_CLICK WM_USER+2002		//tab按钮单击

//tab按钮的状态
enum TabState
{
	TAB_STATE_NOR			= 0,
	TAB_STATE_DOWN			= 1,
};
class MyTabControl : public CWnd
{
	DECLARE_DYNAMIC(MyTabControl)

public:
	MyTabControl();
	virtual ~MyTabControl();

	 bool Create(CWnd* pParent,CRect rc,CString text,DWORD id = 0,DWORD style = WS_VISIBLE|WS_CHILD);  

	DECLARE_MESSAGE_MAP()

public:
	void SetShowText(CString strShowText);

protected:
	CString szClassName;  
	bool m_isMouseHover;		//鼠标是否悬浮
	bool m_isMouseClicked;		//鼠标是否单击
	CString m_strShowText;		//要显示的文字
	CString m_strTabText;		//绘制在tab按钮下的文字

	Image*						m_pImgNor;			//正常时的图片
	Image*						m_pImgHot;			//鼠标悬浮时的图片
	Image*						m_pImgDown;			//单击按下时的图片
	
	void PostClickEvent();
	afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
	afx_msg void OnMouseMove(UINT nFlags, CPoint point);  
	afx_msg void OnMouseHover(UINT nFlags, CPoint point);  
	afx_msg void OnMouseLeave();  
	afx_msg void OnLButtonDown(UINT nFlags, CPoint point);  
	afx_msg void OnLButtonUp(UINT nFlags, CPoint point);  
	afx_msg BOOL OnEraseBkgnd(CDC* pDC);  
	afx_msg void OnPaint();  
	afx_msg void OnSize(UINT nType, int cx, int cy);
	afx_msg LRESULT OnBtnClose(WPARAM wParam, LPARAM lParam);
	virtual BOOL PreTranslateMessage(MSG* pMsg);
public:
	void SetTabState(TabState state){m_tabState = state; Invalidate();}	//设置tab状态
	TabState GetTabState(){return m_tabState;}
	void SetToolTipText(CString spText, BOOL bActivate = TRUE);
	void SetTabIndex(int idx){m_nIndex = idx;}
	int GetTabIndex(){return m_nIndex;}
private:
	DWORD GetComfortSize(HDC hdc, DWORD dwWidth, CString &strText);
private:
	TabState m_tabState;							//tab的状态
	CLhsButton m_btnClose;							//关闭按钮
	CToolTipCtrl*	m_pToolTip;
	CString m_tooltext;
	bool m_bCenterAlign;							//是否居中对齐
	int m_nIndex;									//tab按钮的索引

public:
	afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
};

// MyTabControl.cpp : 实现文件
//

#include "stdafx.h"
#include "../Lander_mini.h"
#include "MyTabControl.h"
#include "memdc.h"
#include "../Utility.h"
// MyTabControl

IMPLEMENT_DYNAMIC(MyTabControl, CWnd)

MyTabControl::MyTabControl()
{
	m_isMouseHover = false;  
	m_isMouseClicked = false;  
	// 注册控件类  
	szClassName = AfxRegisterWndClass(0); 
	m_pImgNor = NULL;
	m_pImgHot = NULL;
	m_pImgDown = NULL;
	m_tabState = TAB_STATE_NOR;
	m_pToolTip = NULL;
	m_bCenterAlign = false;
	m_nIndex = 0;
}

MyTabControl::~MyTabControl()
{
	SAFE_RELEASE(m_pToolTip);
	SAFE_RELEASE(m_pImgNor);
	SAFE_RELEASE(m_pImgHot);
	SAFE_RELEASE(m_pImgDown);
}


BEGIN_MESSAGE_MAP(MyTabControl, CWnd)
	ON_WM_MOUSEMOVE()  
	ON_WM_MOUSEHOVER()  // 此消息系统并不会给我们发送  
	ON_WM_MOUSELEAVE()  
	ON_WM_LBUTTONDOWN()  
	ON_WM_LBUTTONUP()  
	ON_WM_PAINT()  
	ON_WM_SIZE()
	ON_WM_ERASEBKGND()  
	ON_WM_CREATE()
	ON_MESSAGE(MYWM_BTN_CLICK, &MyTabControl::OnBtnClose)
	ON_WM_CTLCOLOR()
END_MESSAGE_MAP()

// MyTabControl 消息处理程序
bool MyTabControl::Create(CWnd* pParent,CRect rc,CString text,DWORD id /* = 0 */,DWORD style /* = WS_VISIBLE|WS_CHILD */)  
{  
	// 动态创建控件  	
	BOOL ret = CWnd::CreateEx(0, szClassName, text, style, rc, pParent, id);
	return ret ? true : false;  
}  

int MyTabControl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	
	//::SetWindowLong(m_hWnd, GWL_EXSTYLE, GetWindowLong(m_hWnd, GWL_EXSTYLE) ^ WS_EX_LAYERED);
	m_pImgNor = CQYUtility::LoadImgFromRes(_T("PNG"), IDB_PNG_TAB_NOR);
	m_pImgHot = CQYUtility::LoadImgFromRes(_T("PNG"), IDB_PNG_TAB_HOT);
	m_pImgDown = CQYUtility::LoadImgFromRes(_T("PNG"), IDB_PNG_TAB_DOWN);
	
	RECT rc = {0, 0, 20, 20};
	m_btnClose.LoadBtnImg(_T("PNG"),IDB_PNG_TAB_CLOSE_NOR, IDB_PNG_TAB_CLOSE_HOT,IDB_PNG_TAB_CLOSE_HOT);
	m_btnClose.Create(this, rc, L"",ID_BTN_MYTAB_CLOSE);		
	m_btnClose.SetToolTipText(_T("关闭")); 		
	EnableToolTips(TRUE);
	return 0;
}

void MyTabControl::PostClickEvent()  
{  
	if (m_tabState == TAB_STATE_DOWN)
		return;		//选中的tab不响应单击了
	// 该函数用来向父窗口发送 单击 消息  
	CWnd* parent = GetParent();  
	if(parent)  
		parent->SendMessage(MYWM_BTN_TAB_CLICK,m_nIndex,0);  	
}  

void MyTabControl::OnMouseHover(UINT nFlags, CPoint point)  
{  
	// 鼠标进入  
	Invalidate();  
}  

void MyTabControl::OnMouseMove(UINT nFlags, CPoint point)
{
	// 只处理鼠标第一次进入时的情况  
	if(!m_isMouseHover)  
	{  
		m_isMouseHover = true;  

		TRACKMOUSEEVENT evt = { sizeof(evt), TME_LEAVE|TME_HOVER, m_hWnd, 0 };  
		TrackMouseEvent(&evt);  

		OnMouseHover(0,CPoint());  
	}  
}

void MyTabControl::OnMouseLeave()  
{  
	// 鼠标离开  
	m_isMouseHover = false;  
	m_isMouseClicked = false;  
	Invalidate();  
}  

void MyTabControl::OnLButtonDown(UINT nFlags, CPoint point)  
{  
	// 鼠标按下  
	m_isMouseClicked = true;  
	Invalidate();  
}  

void MyTabControl::OnLButtonUp(UINT nFlags, CPoint point)  
{  
	// 鼠标松开  
	if(m_isMouseClicked)  
	{  
		m_isMouseClicked = false;  
		Invalidate(); 
		PostClickEvent();  
	}  
}  

BOOL MyTabControl::OnEraseBkgnd(CDC* pDC)  
{  
//	return CWnd::OnEraseBkgnd(pDC);
	return TRUE;    // 阻止擦除背景,防止闪烁  
}  

void MyTabControl::OnPaint()  
{  
	CPaintDC dc(this);   
	CRect rc;  
	GetClientRect(&rc); 
	
	// 采用双缓存,防止闪烁  
	CMemDC memdc(&dc,&rc,TRUE);
	Graphics graphic(memdc);
	if (!m_pImgNor || !m_pImgHot || !m_pImgDown)
	{//没有提供按钮图片就刷下背景
		// 刷背景  
		COLORREF bkgnd = RGB(100,0,0);  
		if(m_isMouseHover)  
		{  
			if(m_isMouseClicked)  
				bkgnd = RGB(250,0,0);  
			else  
				bkgnd = RGB(180,0,0);  
		}  
		memdc.FillSolidRect(&rc,bkgnd);  
	}
	
	if (m_isMouseClicked || m_tabState == TAB_STATE_DOWN)
	{//单击一定画单击状态
		graphic.DrawImage(m_pImgDown, 0, 0, m_pImgDown->GetWidth(), m_pImgDown->GetHeight());
	}
	else if (m_isMouseHover && !m_isMouseClicked)
	{
		//悬浮,但是没单击
		graphic.DrawImage(m_pImgHot, 0, 0, m_pImgHot->GetWidth(), m_pImgHot->GetHeight());		
	}
	else
	{
		graphic.DrawImage(m_pImgNor, 0, 0, m_pImgNor->GetWidth(), m_pImgNor->GetHeight());	
	}

	if (!m_strTabText.IsEmpty())
	{
		// 设置文字字体  
		CFont font;  
		font.CreatePointFont(100,L"宋体"); // 11号字体,该参数与实际字体号有10倍的关系  
		CFont* poldFont = memdc.SelectObject(&font);  
		// 设置文字属性  
		memdc.SetBkMode(TRANSPARENT);  
		if (m_tabState == TAB_STATE_DOWN)
			memdc.SetTextColor(RGB(136,76,25));  
		else
			memdc.SetTextColor(RGB(255,245,190));  
		// 绘制文本  
		DWORD style = DT_SINGLELINE | DT_VCENTER ;   // 文本格式:单行+水平居中+垂直居中  
		//if (m_bCenterAlign)
		//	style |= DT_CENTER;
		CRect fontRect(rc);
		fontRect.left += 13;
		fontRect.right -= 22;
		memdc.DrawText(m_strTabText, -1, &fontRect, style);    // 更多文本显示格式可参考百度百科DrawText说明 
		memdc->SelectObject(poldFont);		
	}
	
	// 使绘制生效  
	graphic.ReleaseHDC(memdc);			
}  


BOOL MyTabControl::PreTranslateMessage(MSG* pMsg) 
{
	if (m_pToolTip)
	{
		if (::IsWindow(m_pToolTip->m_hWnd))
		{
			m_pToolTip->RelayEvent(pMsg);		
		}
	}

	return CWnd::PreTranslateMessage(pMsg);
}


void MyTabControl::OnSize(UINT nType, int cx, int cy) 
{
	CRect rect;
	GetClientRect(&rect);	
	m_btnClose.SetWindowPos(NULL, rect.right - 22, rect.top + 2, 20, 20, SWP_NOZORDER);
}

LRESULT MyTabControl::OnBtnClose(WPARAM wParam, LPARAM lParam)
{
	// 该函数用来向父窗口发送 单击 消息  
	CWnd* parent = GetParent();  
	if(parent != NULL)  
	{  
		parent->SendMessage(MYWM_BTN_TAB_CLOSE, m_nIndex, 0);
	}  
	return 0;
}

void MyTabControl::SetToolTipText(CString spText, BOOL bActivate)
{
	if (m_pToolTip == NULL)
	{
		m_pToolTip = new CToolTipCtrl;
		// Create ToolTip control
		m_pToolTip->Create(this);
		m_pToolTip->Activate(TRUE);
	}

	m_tooltext = spText;

	// If there is no tooltip defined then add it
	if (m_pToolTip->GetToolCount() == 0)
	{
		CRect rectBtn; 
		GetClientRect(rectBtn);
		m_pToolTip->AddTool(this, m_tooltext, rectBtn, 1);
	}

	// Set text for tooltip
	m_pToolTip->UpdateTipText(m_tooltext, this, 1);
	m_pToolTip->SetDelayTime(2000);
	m_pToolTip->Activate(bActivate);
}


DWORD MyTabControl::GetComfortSize(HDC hdc,DWORD dwWidth,CString &strText)
{
	//二分法查找
	DWORD dwComfortSize = 0;
	DWORD dwBeginSize = 0;
	DWORD dwEndSize = strText.GetLength();

	while(TRUE)
	{
		DWORD dwMiddleSize = (dwEndSize + dwBeginSize) / 2;
		if(dwMiddleSize == dwBeginSize || dwMiddleSize == dwEndSize)
		{
			//两个点之间已经没有数值可以检测,退出循环
			dwComfortSize = dwBeginSize;
			break;
		}

		SIZE sizeChk = {0};
		::GetTextExtentPoint(hdc, strText.GetBuffer(), dwMiddleSize, &sizeChk);

		if(sizeChk.cx == dwWidth)
		{
			//数值刚好合适,跳出循环
			dwComfortSize = dwMiddleSize;
			break;
		}
		else if(static_cast<DWORD>(sizeChk.cx) > dwWidth)
		{
			//重新设置边界
			dwEndSize = dwMiddleSize;
		}
		else
		{
			//重新设置边界
			dwBeginSize = dwMiddleSize;
		}

	}

	return dwComfortSize;
}

void MyTabControl::SetShowText(CString strShowText)
{
	m_strShowText = strShowText;

	CRect rect;
	GetClientRect(&rect);
	SIZE sizeEllipsis = {0};
	::GetTextExtentPoint(GetDC()->GetSafeHdc(), strShowText.GetBuffer(), lstrlen(strShowText.GetBuffer()), &sizeEllipsis);
	if (sizeEllipsis.cx  < rect.Width() - 40)
	{//显示区域够宽
		m_bCenterAlign = true;
		m_strTabText = strShowText;
		return;
	}
	memset(&sizeEllipsis,0, sizeof(sizeEllipsis));
	CString ellipsStr = _T("...");
	::GetTextExtentPoint(GetDC()->GetSafeHdc(), ellipsStr.GetBuffer(), lstrlen(ellipsStr.GetBuffer()), &sizeEllipsis);
	DWORD dwMaxDisp = GetComfortSize(GetDC()->GetSafeHdc(), rect.Width() - sizeEllipsis.cx - 20, strShowText);
	if (dwMaxDisp >= strShowText.GetLength())
	{
		m_strTabText = strShowText;
	}
	else
	{
		m_strTabText = m_strShowText.Left(dwMaxDisp);
		m_strTabText += ellipsStr;		
	}	

}



HBRUSH MyTabControl::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
	HBRUSH hbr = CWnd::OnCtlColor(pDC, pWnd, nCtlColor);

	// TODO:  在此更改 DC 的任何属性
//	m_btnClose.SetBkGnd(pDC);
	// TODO:  如果默认的不是所需画笔,则返回另一个画笔
	return hbr;
}

//内存DC类和按钮类见链接: 点击打开链接



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值