//Tab.h
#ifndef _TAB__X_H
#define _TAB__X_H
#define CXOFF 8
#define CYMARGIN 1
#define CXMARGIN 1
//
///
//
class CTabItem
{
public:
CTabItem(CString str);
CTabItem();
virtual ~CTabItem();
///
friend class CMyTabCtrl;
///
private:
CString m_strText; //文本内容
CRect m_rect; //区域
CRgn m_Rgn; //区域
CPoint m_pts[4]; //四个点
public:
void SetText(CString strText);
void GetText(CString &strText);
private:
BOOL HitTest(CPoint pt);
void GetRect(CRect &rc);
protected:
int ComputerRgn(CDC &dc,int x); //计算区域
void GetFourPoint();//得到四个点
int Draw(CDC &dc,BOOL bSelected);//画图
};
//
//
enum{ MTC_SELCHANGED = 1 };
struct NMMYTAB :public NMHDR
{
int nItem;
const CTabItem *pItem;
};
//
//
//
class CMyTabCtrl:public CWnd
{
DECLARE_MESSAGE_MAP()
public:
CMyTabCtrl();
virtual ~CMyTabCtrl();
private:
CPtrList m_lsTabs;
int m_nCurSel;
protected:
int HitTest(CPoint pt);
void InvalidateTab(int iTab,BOOL bErase = TRUE);
public:
virtual BOOL Create(CWnd *pParent,CPoint &pt,UINT nID);
int AddItem(CString strItem);
BOOL RemoveItem(int iPos);
int GetItemCount();
int SelectItem(int iPos);
CTabItem *GetTab(int iPos);
void RecomputeLayout();
protected:
afx_msg void OnPaint();
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
};
#endif
//Tab.cpp
#include "StdAfx.h"
#include "Tab.h"
//
//CTabItem
//
CTabItem::CTabItem()
{
}
CTabItem::CTabItem(CString str)
{
this->m_strText = str;
}
CTabItem::~CTabItem()
{
}
//
//设定文本
void CTabItem::SetText(CString strText)
{
this->m_strText = strText;
}
//得到文本
void CTabItem::GetText(CString &strText)
{
strText = this->m_strText;
}
//单击测试
BOOL CTabItem::HitTest(CPoint pt)
{
return m_Rgn.PtInRegion(pt);
}
//得到矩形区域
void CTabItem::GetRect(CRect &rc)
{
rc = this->m_rect;
}
//
//
//
//得到四个点
void CTabItem::GetFourPoint()
{
m_pts[0] = CPoint( m_rect.left + CXMARGIN , m_rect.top + CYMARGIN );
m_pts[1] = CPoint( m_rect.left + CXMARGIN + CXOFF , m_rect.bottom - CYMARGIN );
m_pts[2] = CPoint( m_rect.right - CXMARGIN - CXOFF , m_rect.bottom - CYMARGIN );
m_pts[3] = CPoint( m_rect.right - CXMARGIN , m_rect.top + CYMARGIN );
}
//计算Rgn,返回宽度
int CTabItem::ComputerRgn(CDC &dc,int x)
{
if(m_Rgn.m_hObject != NULL)
m_Rgn.DeleteObject();
m_rect.SetRectEmpty();
//得到文本内容大小区域
dc.DrawText(m_strText,&m_rect,DT_CALCRECT);
//CXOFF + CXMARGIN
m_rect.right +=2 * (CXOFF + CXMARGIN);
m_rect.bottom = m_rect.top + GetSystemMetrics(SM_CYHSCROLL) + (2*CYMARGIN);
//右移X个单位,
m_rect.OffsetRect(x,0);
//得到四个点
GetFourPoint();
//得到区域
m_Rgn.CreatePolygonRgn(m_pts,4,WINDING);
return m_rect.Width();
}
//画Tab
int CTabItem::Draw(CDC &dc,BOOL bSelected)
{
//前景色,背景色
COLORREF bgclr = bSelected ? RGB(197,214,252) : GetSysColor(COLOR_BTNFACE);
COLORREF fgclr = GetSysColor(COLOR_BTNTEXT);
//设定背景色,前景色
dc.SetBkColor(bgclr);
dc.SetTextColor(fgclr);
//填充区域
CBrush brush(bgclr);
dc.FillRgn(&m_Rgn,&brush);
//黑笔,阴影笔
CPen blackPen(PS_SOLID,1,RGB(0,0,0));
CPen shadowPen(PS_SOLID,1,::GetSysColor(COLOR_BTNSHADOW));
CPen *pOldPen = NULL;
// .--------.
// .----.
//
pOldPen = dc.SelectObject(&blackPen);
dc.MoveTo(m_pts[0]);
dc.LineTo(m_pts[1]);
pOldPen = dc.SelectObject(&shadowPen);
dc.MoveTo(m_pts[1]);
dc.LineTo(m_pts[2]);
pOldPen = dc.SelectObject(&blackPen);
dc.MoveTo(m_pts[2]);
dc.LineTo(m_pts[3]);
if(!bSelected)
{
pOldPen = dc.SelectObject(&shadowPen);
dc.MoveTo(m_pts[2]);
dc.LineTo(m_pts[3]);
}
dc.SelectObject(pOldPen);
CFont font;
font.CreatePointFont(120,"宋体");
CFont *pOldFont = dc.SelectObject(&font);
CRect rc = m_rect;
rc.DeflateRect( CXOFF + CXMARGIN , CYMARGIN );
dc.DrawText(m_strText,&rc,DT_CENTER | DT_VCENTER | DT_SINGLELINE );
dc.SelectObject(pOldFont);
return rc.right;
}
//
///CMyTabCtrl
//
BEGIN_MESSAGE_MAP(CMyTabCtrl , CWnd)
ON_WM_PAINT()
ON_WM_LBUTTONDOWN()
END_MESSAGE_MAP()
CMyTabCtrl::CMyTabCtrl()
{
m_nCurSel = 0;
}
CMyTabCtrl::~CMyTabCtrl()
{
if(!m_lsTabs.IsEmpty())
{
m_lsTabs.RemoveAll();
}
}
//根据坐标来Create一个TabCtrl
BOOL CMyTabCtrl::Create(CWnd *pParent,CPoint &pt,UINT nID)
{
ASSERT(pParent);
LPCTSTR lpClassName=_T("MyTabCtrl");
WNDCLASS wc={0};
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = ::CreateSolidBrush(::GetSysColor(COLOR_BTNFACE));
wc.hCursor = LoadCursor(NULL , IDC_ARROW );
wc.hIcon = NULL;
wc.hInstance = AfxGetInstanceHandle();
wc.lpszClassName = lpClassName;
wc.lpszMenuName = NULL;
wc.style = CS_VREDRAW | CS_HREDRAW;
wc.lpfnWndProc = (WNDPROC)::DefWindowProc;
if(!AfxRegisterClass(&wc))
{
TRACE("**********CMyTabCtrl::AfxRegisterClass Failed!\n");
return FALSE;
}
CRect rc(pt.x , pt.y , 30 + pt.x , 30+pt.y);
if(!CWnd::Create(lpClassName,NULL,WS_CHILD | WS_VISIBLE,rc,pParent,nID))
{
TRACE("**********CMyTabCtrl::Create Failed!\n");
return FALSE;
}
return TRUE;
}
//增加一项
int CMyTabCtrl::AddItem(CString strItem)
{
CTabItem *pTab = new CTabItem(strItem);
m_lsTabs.AddTail(pTab);
return m_lsTabs.GetCount();
}
//移除一项
BOOL CMyTabCtrl::RemoveItem(int iPos)
{
POSITION pos = m_lsTabs.FindIndex(iPos);
if(pos)
{
CTabItem *pTab = (CTabItem*)m_lsTabs.GetAt(pos);
delete pTab;
}
return pos != NULL;
}
//得到有多少个项
int CMyTabCtrl::GetItemCount()
{
return m_lsTabs.GetCount();
}
//得到指定位置的CTabItem对像
CTabItem* CMyTabCtrl::GetTab(int iPos)
{
int n = GetItemCount();
ASSERT(iPos < n);
POSITION pos = m_lsTabs.FindIndex(iPos);
if(pos)
{
CTabItem *pTab = (CTabItem*)m_lsTabs.GetAt(pos);
return pTab;
}
return NULL;
}
//单击测试
int CMyTabCtrl::HitTest(CPoint pt)
{
CRect rc;
GetClientRect(rc);
if(rc.PtInRect(pt))
{
int n = GetItemCount();
for(int i = 0 ; i < n ; i++)
{
if(GetTab(i)->HitTest(pt))
{
return i;
}
}
}
return -1;
}
//使指定的位置的Tab无效
void CMyTabCtrl::InvalidateTab(int iTab,BOOL bErase /* = TRUE*/)
{
CRect rc;
GetTab(iTab)->GetRect(rc);
InvalidateRect(rc,bErase);
}
//选择一项
int CMyTabCtrl::SelectItem(int iPos)
{
int nTemp = m_nCurSel;
if(iPos < 0 || iPos >=GetItemCount() )
return -1;
if(iPos == m_nCurSel)
return iPos;
//擦除以前的
InvalidateTab(m_nCurSel);
m_nCurSel = iPos;
//绘画现在的
InvalidateTab(m_nCurSel);
return nTemp;
}
//绘画
void CMyTabCtrl::OnPaint()
{
CPaintDC dc(this);
CRect rc;
GetClientRect(rc);
int n = GetItemCount();
CTabItem *pCurTab = NULL;
for(int i = 0 ; i < n ; i++)
{
CTabItem *pTab = GetTab(i);
ASSERT(pTab);
if(i==m_nCurSel)
{
pCurTab = pTab;
}
else
pTab->Draw(dc,FALSE);
}
//画现在的
if(pCurTab)
pCurTab->Draw(dc , TRUE);
}
//发送WM_NOTIFY
void CMyTabCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{
int i = HitTest(point);
if(i >=0 && i !=m_nCurSel)
{
//使其选中
SelectItem(i);
NMMYTAB nm;
nm.nItem = i;
nm.pItem = GetTab(i);
nm.hwndFrom = GetSafeHwnd();
nm.idFrom = GetDlgCtrlID();
nm.code = MTC_SELCHANGED;
GetParent()->SendMessage(WM_NOTIFY,nm.idFrom,(LPARAM)&nm);
}
}
//重新计算区域
void CMyTabCtrl::RecomputeLayout()
{
CClientDC dc(this);
int x = 0;
int n = GetItemCount();
CTabItem *pTab = NULL;
for(int i = 0 ; i < n ; i++)
{
pTab = GetTab(i);
x+= (pTab->ComputerRgn(dc,x) - CXMARGIN - CXOFF);
}
//自动调整窗口位置
CRect rc;
GetWindowRect(rc);
CRect temp;
pTab->GetRect(temp);
rc.right = rc.left + x + CXOFF + CXMARGIN;
rc.bottom = rc.top + temp.Height();
ScreenToClient(rc);
MoveWindow(rc,TRUE);
}