自定义MFC中的选项卡窗口控件CCoolTabCtrl

时间:2021-03-08 18:04:17

转载请标明是引用于 http://blog.csdn.net/chenyujing1234

欢迎大家提出意见,一起讨论!

参考代码:(VS2005)

http://www.rayfile.com/zh-cn/files/4a171bcf-9dd2-11e1-9e93-0015c55db73d/

在MFC中有TabPage控件,但是若想在控件里添加一个按钮或是树型控件,就得自己写控件。

最近最到这个问题,于是参考别人的代码下自己写了此控件。

效果图如下:

自定义MFC中的选项卡窗口控件CCoolTabCtrl

 

1、设计过程

步骤一:  设计每个选择页的类CPageItem
class CPageItem
	{
		friend class CCoolTabCtrl;

		CWnd*		m_pWnd;		///窗口,可以为NULL
		UINT		m_nStyle;	///窗口类型,0:普通,1:动态创建
		CString		m_sText;	///文字
		HICON		m_hIcon;	///图标
	public:
		CRect		m_rect;		
	public:
		void SetPageStyle(UINT nStyle)
		{
			m_nStyle = nStyle;
		}

		UINT GetAreaWidth(CDC *pDC);
		void Draw(CDC *pDC,UINT nStyle,BOOL bActive);
	};


 

///////取得需要占用的宽度/////
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);
		}
}


在CCoolTabCtrl::CPageItem::Draw中根据m_rect绘制。那么m_rect是哪里得来的呢?

肯定是在包容它的窗器CCoolTabCtrl中传给它的。这发生在CCoolTabCtrl::AutoSize().

步骤一:  设计选项卡窗口控件CCoolTabCtrl

设计类

/////////////////////////////////////////////////////////////////////////////
// CCoolTabCtrl window

class CCoolTabCtrl : public CWnd
{
public:
	class CPageItem
	{
		friend class CCoolTabCtrl;

		CWnd*		m_pWnd;		///窗口,可以为NULL
		UINT		m_nStyle;	///窗口类型,0:普通,1:动态创建
		CString		m_sText;	///文字
		HICON		m_hIcon;	///图标
	public:
		CRect		m_rect;		
	public:
		void SetPageStyle(UINT nStyle)
		{
			m_nStyle = nStyle;
		}

		UINT GetAreaWidth(CDC *pDC);
		void Draw(CDC *pDC,UINT nStyle,BOOL bActive);
	};
	DECLARE_DYNCREATE(CCoolTabCtrl)
// Construction
public:
	CCoolTabCtrl();

// Attributes
public:
// Operations
public:

// Overrides
	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CCoolTabCtrl)
	//}}AFX_VIRTUAL

// Implementation
public:
	void SetStyleMonoSpace(BOOL bEnable = TRUE);
	void SetStyleDirection(int Direction);		///Direction取值:TCS_UP,TCS_DOWN
	void SetStyleAnimate(BOOL bEnable = TRUE);	///允许动画bEnable = TRUE,否则为FALSE
	void UpdateWindow();
	BOOL m_bEraseBkgnd;
	UINT GetStyle();
	void SetStyle(UINT style);
	void DrawFrame(CDC *pDC);
	void* GetPageItem(UINT nIndex);
	void SetActivePage(int nIndex);
	BOOL AddPage(CRuntimeClass* pClass,UINT nIDTemplate,LPCTSTR sText,UINT IconID = NULL);
	CPageItem* AddPage(CWnd *pWnd,LPCTSTR sText,UINT IconID = NULL);
	void AutoSize();
	void GetClientRect(LPRECT lpRect );
	BOOL Create(UINT wStyle, const CRect & rect, CWnd * pParentWnd, UINT nID);
	virtual ~CCoolTabCtrl();

	// Generated message map functions
protected:
	//{{AFX_MSG(CCoolTabCtrl)
	afx_msg void OnPaint();
	afx_msg BOOL OnEraseBkgnd(CDC* pDC);
	afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
	afx_msg void OnSizing(UINT fwSide, LPRECT pRect);
	afx_msg void OnSize(UINT nType, int cx, int cy);
	afx_msg void OnTimer(UINT nIDEvent);
	afx_msg BOOL OnNotify( WPARAM wParam, LPARAM lParam, LRESULT* pResult );
	afx_msg int  OnCreate(LPCREATESTRUCT lpCreateStruct);
	afx_msg void OnDestroy();	
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
private:
	CFont		m_font;
	int			m_nActivePage;
	UINT		m_nStyle;
	UINT		m_nBorder;
	CPtrList	m_PageList;
};


最重要的创建函数OnCreate调用了CWnd类的OnCreate后就创建字体而已.

int CCoolTabCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if(CWnd::OnCreate(lpCreateStruct) == -1)
		return -1;
	
	LOGFONT logFont;
	ZeroMemory((void*)&logFont,sizeof(logFont));
	wcscpy_s(logFont.lfFaceName, L"宋体");
	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;
}


 把页面窗口添加到适合位置,当新建它的选项卡

// 把页面窗口添加到适合位置,当新建它的选项卡
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;
}


在OnPain里重新绘制3D主框和每个选项

// 重新绘制3D主框和每个选项
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);
}


 

 

2、使用方法

在主界面中添加CCoolTabCtrl类成员。

CCoolTabCtrl m_TabCtrl;     // 选项卡控件, 用于管理子窗口

 

选项卡控件创建

 // 创建一个选项卡控件
 m_TabCtrl.Create(TCS_DOWN | WS_CHILD | WS_VISIBLE, CRect(0,0,100,100), &m_wndCtrlBar, 125);


TabCtrl作为一个容器添加新的控件

// 将树型控件加入到TabCtrl中
 m_TabCtrl.AddPage(&m_TreeCtrl, L"文件目录", IDI_DIR);
 m_TabCtrl.AddPage(RUNTIME_CLASS(CPrevDlg), IDD_PREV, L"位图浏览", IDI_DIR);

 

调整大小并激活选项页

m_TabCtrl.UpdateWIndow();