gusucode.com > MFC编程,实现类似VC6.0的界面设计源码程序 > MFC编程,实现类似VC6.0的界面设计源码程序/VCface/bardemo/CoolTabCtrl.cpp

    ////////////////////////////////////////////////////////////////
// CoolTabCtrl.cpp : implementation file                      //
//															  //
// Copyright 2001 WangJun									  //
// All Rights Reserved.										  //
//															  //
// Email: wangjun98@sohu.com								  //
// URL:   www.vckbase.com									  //
//															  //
// 1.0     2001/9/30   First release version.				  //
//															  //
// 2004/2/8 添加对WM_NOTIFY消息的处理						  //
// 2005/2/2 修正内存泄漏						  //
//                                                            //
////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "CoolTabCtrl.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CCoolTabCtrl

IMPLEMENT_DYNCREATE(CCoolTabCtrl, CWnd)

#define	ITEMBUTTON_HEIGHT		23

static CPen _penW(PS_SOLID,1 ,RGB(255,255,255));
static CPen _penB(PS_SOLID,1 ,RGB(0,0,0));
static CPen _pen3DFace(PS_SOLID,1,GetSysColor(COLOR_3DFACE));
static CPen _pen3DLight(PS_SOLID,1,GetSysColor(COLOR_3DLIGHT));
static CPen _pen3DShadow(PS_SOLID,1,GetSysColor(COLOR_3DSHADOW));
static CPen _pen3DDKShadow(PS_SOLID,1,GetSysColor(COLOR_3DDKSHADOW));


CCoolTabCtrl::CCoolTabCtrl()
{
	m_nStyle = TCS_DOWN;
	m_nActivePage = -1;
	m_nBorder = 1;
	m_bEraseBkgnd = TRUE;
}

CCoolTabCtrl::~CCoolTabCtrl()
{
	POSITION pos;
	CPageItem* pItem;
	for(pos=m_PageList.GetHeadPosition();pos!=NULL;)
	{
		pItem=(CPageItem*)m_PageList.GetNext(pos);
		if(pItem)
		{	
			if(pItem->m_nStyle == 1 && pItem->m_pWnd) // 动态创建
			{
				pItem->m_pWnd->DestroyWindow();
				delete pItem->m_pWnd;
			}
			delete pItem;
			pItem=NULL;
		}
	}
	m_PageList.RemoveAll();
}


BEGIN_MESSAGE_MAP(CCoolTabCtrl, CWnd)
	//{{AFX_MSG_MAP(CCoolTabCtrl)
	ON_WM_PAINT()
	ON_WM_ERASEBKGND()
	ON_WM_LBUTTONDOWN()
	ON_WM_SIZING()
	ON_WM_SIZE()
	ON_WM_TIMER()
	ON_WM_CREATE()
	ON_WM_DESTROY()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CCoolTabCtrl message handlers

BOOL CCoolTabCtrl::Create(UINT wStyle, const CRect &rect, CWnd *pParentWnd, UINT nID)
{
	m_nStyle = wStyle & TCS_MASK;
	if(m_nStyle == 0)
		m_nStyle = TCS_UP;
	if (CWnd::Create(AfxRegisterWndClass(CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW, AfxGetApp()->LoadStandardCursor(IDC_ARROW), (HBRUSH)GetStockObject(LTGRAY_BRUSH), NULL),
						NULL,
						wStyle&~TCS_MASK | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
						rect, 
						pParentWnd, 
						nID))
	{
		
		return TRUE;
	}
	return FALSE;
}

BOOL CCoolTabCtrl::OnEraseBkgnd(CDC* pDC) 
{
	if(m_bEraseBkgnd)
	{
		CRect rect;
		GetWindowRect(&rect);
		ScreenToClient(&rect);
		CBrush brush(GetSysColor(COLOR_3DFACE));
		pDC->FillRect(rect,&brush);
	}
	return TRUE;
}

void CCoolTabCtrl::OnPaint() 
{
	CPaintDC	dc(this);
	CPen	*pOldPen = dc.GetCurrentPen();
	CFont	*pOldFont = dc.SelectObject(&m_font);
	int		nOldBkMode = dc.SetBkMode(TRANSPARENT);
	CPageItem	*pItem;
	POSITION	pos;
	int		nItemIndex = 0;
	
	DrawFrame(&dc);

	for(pos=m_PageList.GetHeadPosition();pos!=NULL;nItemIndex++)
	{
		pItem=(CPageItem*)m_PageList.GetNext(pos);
		if(pItem)
		{
			pItem->Draw(&dc,m_nStyle,(m_nActivePage==nItemIndex)?TRUE:FALSE);
		}

	}
	dc.SetBkMode(nOldBkMode);
	dc.SelectObject(pOldFont);
	dc.SelectObject(pOldPen);
}


CCoolTabCtrl::CPageItem* CCoolTabCtrl::AddPage(CWnd *pWnd, LPCTSTR sText, UINT IconID)
{
	ASSERT(pWnd);
	ASSERT(IsWindow(pWnd->m_hWnd));

	CPageItem *pItem = NULL;
	pItem = new CPageItem();
	pItem->m_pWnd = pWnd;
	pItem->m_nStyle = 0;	//Window
	pItem->m_sText = sText;
	if(IconID)
		pItem->m_hIcon = AfxGetApp()->LoadIcon(IconID);
	else
		pItem->m_hIcon = NULL;

	CRect	rect;
	GetClientRect(rect);
	pWnd->MoveWindow(rect);

	m_PageList.AddTail(pItem);

	// 如果添加的Page index不等于m_nActivePage, 则隐藏
	if(m_nActivePage != m_PageList.GetCount())
	{
		pWnd->ShowWindow(SW_HIDE);
	}

	return pItem;
}

BOOL CCoolTabCtrl::AddPage(CRuntimeClass* pClass,UINT nIDTemplate, LPCTSTR sText, UINT IconID)
{
	CDialog *pDlg = (CDialog*)pClass->CreateObject();
	if(pDlg != NULL)
	{
		if(pDlg->Create(nIDTemplate,this))
		{
			CCoolTabCtrl::CPageItem *pItem = AddPage(pDlg, sText, IconID);
			if(pItem)
			{
				pItem->SetPageStyle(1);
				return TRUE;
			}
		}
	}
	
	return FALSE;
}


void CCoolTabCtrl::GetClientRect(LPRECT lpRect)
{
	CWnd::GetClientRect(lpRect);
	if(m_nStyle&TCS_DOWN)
	{
		lpRect->left += 2;
		lpRect->right -= 2;
		lpRect->top += 2;
		lpRect->bottom -= ITEMBUTTON_HEIGHT;
	}
	else if(m_nStyle&TCS_UP)
	{
		lpRect->left += 2;
		lpRect->right -= 2;
		lpRect->top += ITEMBUTTON_HEIGHT;
		lpRect->bottom -= 2;
	}
}

///////取得需要占用的宽度/////
UINT CCoolTabCtrl::CPageItem::GetAreaWidth(CDC *pDC)
{
	UINT width = pDC->GetTextExtent(m_sText).cx;
	if(m_hIcon)
		width += 18;
	return width + 9;
}

void CCoolTabCtrl::CPageItem::Draw(CDC *pDC, UINT nStyle, BOOL bActive)
{
	CRect rect = m_rect;
	if(nStyle&TCS_DOWN)
	{
		if(bActive)
		{
			rect.top -= 2;
			CBrush brush(GetSysColor(COLOR_3DFACE));
			pDC->FillRect(rect,&brush);
			rect.top += 1;
		}
		else
			rect.bottom -= 1;
		CBrush brush(GetSysColor(COLOR_3DFACE));
		pDC->FillRect(m_rect,&brush);
		pDC->SelectObject(&_penW);
		pDC->MoveTo(rect.left,rect.top);
		pDC->LineTo(rect.left,rect.bottom-1);
		
		pDC->SelectObject(&_pen3DShadow);
		pDC->MoveTo(rect.left+1,rect.bottom-2);
		pDC->LineTo(rect.left+1,rect.bottom-1);
		pDC->LineTo(rect.right-1,rect.bottom-1);
		pDC->MoveTo(rect.right-2,rect.bottom-2);
		pDC->LineTo(rect.right-1,rect.bottom-2);
		pDC->LineTo(rect.right-1,rect.top-1);

		pDC->SelectObject(&_penB);
		pDC->MoveTo(rect.left+2,rect.bottom);
		pDC->LineTo(rect.right-2,rect.bottom);
		pDC->LineTo(rect.right,rect.bottom-2);
		pDC->MoveTo(rect.right,rect.top);
		pDC->LineTo(rect.right,rect.bottom-1);
	
		rect.top -= 1;
	}//end of TCS_DOWN
	else if(nStyle&TCS_UP)
	{
		CBrush brush(GetSysColor(COLOR_3DFACE));
		if(bActive)
		{
			rect.bottom += 1;
			pDC->FillRect(rect,&brush);
			rect.bottom -= 1;
		}
		else
		{
			rect.top += 2;
			pDC->FillRect(rect,&brush);
		}
		pDC->SelectObject(&_penW);
		pDC->MoveTo(rect.left,rect.bottom);
		pDC->LineTo(rect.left,rect.top + 2);
		pDC->LineTo(rect.left + 2,rect.top);
		pDC->LineTo(rect.right,rect.top);

		pDC->SelectObject(&_pen3DShadow);
		pDC->MoveTo(rect.right - 1,rect.top);
		pDC->LineTo(rect.right - 1,rect.bottom);
			
		pDC->SelectObject(&_penB);
		pDC->MoveTo(rect.right,rect.top + 1);
		pDC->LineTo(rect.right,rect.bottom);	
	}
	///////////调整位置//////////
		rect.left += 5;
		rect.right -= 2;
		///////////显示图标//////////
		if(rect.Width() > 16 && m_hIcon != NULL)
		{
			::DrawIconEx(pDC->m_hDC,rect.left,rect.top + 3,m_hIcon,16,16,0,NULL,DI_NORMAL);
			rect.left += 18;
		}
		if (!m_sText.IsEmpty())
		{
			///////////显示文字//////////
			rect.top += 5;
			CString sText = m_sText;
			int l = sText.GetLength();
			int i;
			for(i=0;i<10 && pDC->GetTextExtent(sText).cx > rect.Width();i++,l-=2)
				sText = sText.Left(l-2);
			if(i > 0)
			{
				sText = sText.Left(l-2);
				sText += "...";
			}
			pDC->DrawText(sText, &rect, DT_LEFT /*| DT_VCENTER */| DT_SINGLELINE);
		}
}

////调整尺寸////
void CCoolTabCtrl::AutoSize()
{
	UINT PageCount = m_PageList.GetCount();
	if(PageCount < 1) return;
	CPageItem	*pItem;
	POSITION	pos;
	CRect		rect,ClientRect,ItemRect;

	GetClientRect(ClientRect);
	ClientRect.DeflateRect(m_nBorder+1,m_nBorder+1);
	GetWindowRect(rect);
	ScreenToClient(rect);

	CDC* pDC = GetDC();
	CFont	*pOldFont = pDC->SelectObject(&m_font);

	if(m_nStyle&TCS_DOWN)
	{
		rect.left += 6;
		rect.right -= 6;
		rect.bottom -= 1;
		rect.top = rect.bottom - ITEMBUTTON_HEIGHT + 1;
	}
	else if(m_nStyle&TCS_UP)
	{
		rect.left += 2;
		rect.right -= 6;
		rect.bottom = rect.top + ITEMBUTTON_HEIGHT;
	}
	ItemRect = rect;
	int AreaWidth = 0,ItemMaxWidth,ItemIndex=0;
	ItemMaxWidth = rect.Width()/m_PageList.GetCount();
	BOOL	bMonoSpace = ((m_nStyle&TCS_MONOSPACE) == TCS_MONOSPACE)?1:0;
	////////设置按钮初始宽度,并得到按钮所需占用的总宽度///////
	for(pos=m_PageList.GetHeadPosition();pos!=NULL;ItemIndex++)
	{
		pItem=(CPageItem*)m_PageList.GetNext(pos);
		if(pItem)
		{
			if(!bMonoSpace)
				ItemMaxWidth = pItem->GetAreaWidth(pDC);
			AreaWidth += ItemMaxWidth;
			ItemRect.right = ItemRect.left+ItemMaxWidth-1;
			pItem->m_rect = ItemRect;
			ItemRect.left = ItemRect.right + 1;
			if(pItem->m_pWnd)
				pItem->m_pWnd->MoveWindow(ClientRect);
		}
	}
	////////当需要的空间大于实际空间时进行调整////
	if(AreaWidth > rect.Width() && !bMonoSpace)
	{
		ItemRect = rect;
		int AreaWidth,MaxWidth = rect.Width()/PageCount;
		for(pos=m_PageList.GetHeadPosition();pos!=NULL;)
		{
			pItem=(CPageItem*)m_PageList.GetNext(pos);
			if(pItem)
			{
				AreaWidth = pItem->GetAreaWidth(pDC);
				ItemMaxWidth = (ItemMaxWidth < AreaWidth)?MaxWidth:AreaWidth;
				ItemRect.right = ItemRect.left+ItemMaxWidth;
				pItem->m_rect = ItemRect;
				ItemRect.left = ItemRect.right + 1;
			}
		}
	}
	pDC->SelectObject(pOldFont);
	ReleaseDC(pDC);
}

void CCoolTabCtrl::SetActivePage(int nIndex)
{
	if(nIndex == m_nActivePage)
		return;
	CPageItem *pOldItem,*pItem;
	if(m_nActivePage >= 0)
	{
		pOldItem = (CPageItem*)GetPageItem(m_nActivePage);
		if(pOldItem)
		{
			pOldItem->m_pWnd->ShowWindow(SW_HIDE);
		}
	}
	pItem = (CPageItem*)GetPageItem(nIndex);
	if(!pItem) return;
	m_nActivePage = nIndex;
	if(m_nStyle&TCS_ANIMATE)
		SetTimer(100,15,NULL);///为了在95或NT4下也有动画效果,没有使用AnimateWindow函数
	else
		pItem->m_pWnd->ShowWindow(SW_SHOW);
}

void* CCoolTabCtrl::GetPageItem(UINT nIndex)
{
	CPageItem *pItem = NULL;
	POSITION pos = m_PageList.FindIndex(nIndex);
	if(pos)
		pItem = (CPageItem*)m_PageList.GetAt(pos);
	return pItem;
}

void CCoolTabCtrl::UpdateWindow()
{
 	AutoSize();
 	if(m_nActivePage < 0)
 		SetActivePage(0);
 	else
 		SetActivePage(m_nActivePage);
 	Invalidate();
}

void CCoolTabCtrl::OnLButtonDown(UINT nFlags, CPoint point) 
{
	UINT nItemIndex=0;
	POSITION pos;
	CPageItem *pItem;
	for(pos=m_PageList.GetHeadPosition();pos!=NULL;nItemIndex++)
	{
		pItem=(CPageItem*)m_PageList.GetNext(pos);
		if(pItem)
		{
			if(pItem->m_rect.PtInRect(point))
			{
				SetActivePage(nItemIndex);
				Invalidate();
				break;
			}
		}
	}
	CWnd::OnLButtonDown(nFlags, point);
}

void CCoolTabCtrl::OnSizing(UINT fwSide, LPRECT pRect) 
{
	CWnd::OnSizing(fwSide, pRect);
	m_bEraseBkgnd = FALSE;
	AutoSize();
}

void CCoolTabCtrl::OnSize(UINT nType, int cx, int cy) 
{
	CWnd::OnSize(nType, cx, cy);
	m_bEraseBkgnd = TRUE;
	AutoSize();
	Invalidate();
}

void CCoolTabCtrl::DrawFrame(CDC *pDC)
{
	CRect rect;
	GetClientRect(&rect);
	switch(m_nBorder)
	{
	case 1:
			pDC->Draw3dRect(rect,RGB(0xff,0xff,0xff),RGB(0,0,0));
		break;
	case 2:
			pDC->Draw3dRect(rect,RGB(0xff,0xff,0xff),RGB(0,0,0));
			rect.DeflateRect(1, 1);
			pDC->Draw3dRect(rect, GetSysColor(COLOR_3DFACE), GetSysColor(COLOR_3DSHADOW));
		break;
	default:break;
	}
}



void CCoolTabCtrl::SetStyle(UINT style)
{
	m_nStyle = style;
}

UINT CCoolTabCtrl::GetStyle()
{
	return m_nStyle;
}

void CCoolTabCtrl::OnTimer(UINT nIDEvent) 
{
	static	step,times = 10;
	UINT	width;
	CRect	rect;
	GetClientRect(&rect);
	rect.DeflateRect(m_nBorder+1,m_nBorder+1);
	POSITION pos = m_PageList.FindIndex(m_nActivePage);
	if(pos)
	{
		CPageItem *pItem = (CPageItem*)m_PageList.GetAt(pos);
		if(pItem)
		{
			width = rect.Width();
			if(times == 10)
			{
				rect.right = 10;
				rect.left = rect.right - width + 1;
				step = width/times;
				times--;
				m_bEraseBkgnd = FALSE;
				pItem->m_pWnd->ShowWindow(SW_SHOW);
			}
			else
			{
				if(times <= 0)
				{
					times = 10;
					KillTimer(nIDEvent);
					m_bEraseBkgnd = TRUE;
				}
				else
				{
					rect.right = width - times*step;
					rect.left = rect.right - width + 1;
					times--;
				}
			}
			pItem->m_pWnd->MoveWindow(rect);
		}
	}
}

void CCoolTabCtrl::SetStyleAnimate(BOOL bEnable)
{
	UINT style = GetStyle();
	if(bEnable)
		style |= TCS_ANIMATE;
	else
		style &= ~TCS_ANIMATE;
	SetStyle(style);
}

void CCoolTabCtrl::SetStyleDirection(int Direction)
{
	UINT style = GetStyle();
	switch(Direction)
	{
	case TCS_DOWN:
		style &= ~TCS_UP;
		style |= TCS_DOWN;
		break;
	case TCS_UP:
	default:
		style &= ~TCS_DOWN;
		style |= TCS_UP;
		break;
	}
	SetStyle(style);
	UpdateWindow();
}

void CCoolTabCtrl::SetStyleMonoSpace(BOOL bEnable)
{
	UINT style = GetStyle();
	if(bEnable)
		style |= TCS_MONOSPACE;
	else
		style &= ~TCS_MONOSPACE;
	SetStyle(style);
	UpdateWindow();
}

BOOL CCoolTabCtrl::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
	// 将WM_NOTIFY消息转交给父窗口处理
	GetParent()->SendMessage(WM_NOTIFY, wParam, lParam);
	*pResult = 0;
	
	return TRUE;
}

int CCoolTabCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if(CWnd::OnCreate(lpCreateStruct) == -1)
		return -1;
	
	LOGFONT logFont;
	ZeroMemory((void*)&logFont,sizeof(logFont));
	strcpy(logFont.lfFaceName,"宋体");
	logFont.lfHeight = -12;
	logFont.lfWeight = 400;
	logFont.lfCharSet = GB2312_CHARSET;
	logFont.lfOutPrecision = 3;
	logFont.lfClipPrecision = 2; 
	logFont.lfQuality = 1;
	logFont.lfPitchAndFamily = 2;
	m_font.CreateFontIndirect(&logFont);
	SetFont(&m_font);

	return 0;
}

void CCoolTabCtrl::OnDestroy()
{
	CWnd::OnDestroy();
}