转载请标明是引用于 http://blog.youkuaiyun.com/chenyujing1234
欢迎大家提出意见,一起讨论!
参考代码:(VS2005)
http://www.rayfile.com/zh-cn/files/4a171bcf-9dd2-11e1-9e93-0015c55db73d/
在MFC中有TabPage控件,但是若想在控件里添加一个按钮或是树型控件,就得自己写控件。
最近最到这个问题,于是参考别人的代码下自己写了此控件。
效果图如下:
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();