转载请标明是引用于 http://blog.csdn.net/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();