Visual C++中Tab View的多种实现方法
本文实例讲述了VisualC++中TabView的多种实现方法,分享给大家供大家参考。具体如下:
一、引言
标签控件(TabControl)是VC++编程中经常使用的控件之一,它允许在单个对话框或窗口中设置多个页面,每个页面代表一组控件。当某个页面的标签被选中时,该页面内的控件就会被显示出来。标签控件使得在有限的窗口空间内可以显示更多的信息,而且分类清晰。同时,VC++提供了以文档/视图(Document/View)结构方式开发应用程序的简单方法,在文档中保存数据,在视图中显示数据。无论是在SDI还是MDI的程序中,每个文档可以对应一个或多个是视图,但常常在显示数据时,需要将同一组数据用不同的视图显示,如列表视图、树型视图等,或者用一个视图显示一部分数据,用另一个视图显示另一部分数据,并且希望能在同一个显示区显示,在需要时进行切换。将标签控制运用到多视图的切换中,就形成了TabView。
通过上面的分析,我们不难发现,实现一个TabView主要要完成以下两方面的工作:
①实现一个标签窗口。它要具有绘制窗口、响应用户选择、判断处理用户选择等功能。本文对TabView实现方法的分类就是根据标签窗口不同划分的。
②多个视图之间的切换。根据标签窗口判断用户选择的结果,从多个视图中选择一个,在显示区中显示。
本文分析和总结了三种TabView的实现方法:
1)利用CTabCtrl控件实现TabView.
2)利用CSheetCtrl标签选择窗口实现TabView.
3)利用静态分割窗口实现TabView.
二、CTabCtrl控件实现TabView
CTabCtrl是MFC类库中定义的标准控件类,通过对消息TCN-SELCHANGE的处理以及运用函数GetCurSel()、SetCurSel()等,可以很好地完成响应、判断和设置标签控制的工作,因此利用CTabCtrl控件实现TabView是较容易的方法。
1.实现的主要类
//要切换显示的视窗口类
classCMyView1:publicCListView
classCMyView2:publicCView
//派生的标签控件类
classCViewTabCtrl:publicCTabCtrl
//定义了Tabview的主窗口
classCTabCtrlView:publicCWnd
{
protected:
CViewTabCtrlm_TabCtl;
…
}
classCMainFrame:publicCFrameWnd
{
CTabCtrlViewm_TabView;
…
}2.窗口之间的父子关系以及位置关系
下述代码确定各窗口之间的位置关系。
voidCTabCtrlView::RecalcLayout()
{ …
CRectrect;
//CTabCtrlView窗口的客户区大小
GetClientRect(&rect);
m_TabCtl.RecalcLayout(rect,pWnd);
…
}
voidCViewTabCtrl::RecalcLayout(CRect&rect,CWnd*wnd)
{
//标签控件占据CTabCtrlView窗口的客户区
SetWindowPos(NULL,rect.left,rect.top,rect.right-rect.left,
rect.bottom-rect.top,SWP_NOZORDER);
//调整要显示的视窗口位置,使其占据标签控件的显示区
AdjustRect(FALSE,&rect);
wnd->SetWindowPos(NULL,rect.left,rect.top,rect.right-rect.left,
rect.bottom-rect.top,SWP_NOZORDER);
}3.多个视之间切换的实现
视的切换主要完成下面的工作:
//步骤1:设置当前活动的子窗口的ID
CView*pOldActiveView=GetActiveView();
::SetWindowLong(pOldActiveView->m_hWnd,GWL_ID,m_nCurrentExample);
//步骤2:生成一个新的与所选择的视窗口对应的运行时类
CRuntimeClass*pNewViewClass;
switch(nViewID)//nViewID各个视图的标识
{
caseID_MYVIEW1:
pNewViewClass=RUNTIME_CLASS(CMyView1);
break;
caseID_MYVIEW2:
pNewViewClass=RUNTIME_CLASS(CMyView2);
break;
default:
ASSERT(0);
return;
}
//步骤3:准备新视图类的相关上下文,创建新的视
CCreateContextContext;
Context.m_pNewViewClass=pNewViewClass;
Context.m_pCurrentDoc=GetActiveDocument();
CView*pNewView=m_TabView.CreateView(pNewViewClass,CSize(100,100),&Context);
if(pNewView!=NULL)
{
//步骤4:显示新的视图
pNewView->ShowWindow(SW_SHOW);
SetActiveView(pNewView);
…
//步骤5:关闭旧的视图
pOldActiveView->DestroyWindow();
}在视图切换过程中,都需要重新生成新视图,关闭旧的视图。但在某些情况下,希望多个视图窗口能够同时存在,在某时刻只显示一个,而隐藏其它的窗口。可以通过定义下面的数据结构和变量,将每次加入的新视图的窗口信息保存。
typedefstruct
{
CWnd*pWnd; //窗口指针
charszLabel[32];//标签窗口对应该视图的字符串
}TCB_ITEM;
//将每次如入的视图信息保存到列表中
CList<TCB_ITEM*,TCB_ITEM*>m_Views;
在切换时,通过函数SetWindowPos()中设置参数SWP_SHOWWINDOW或SWP_HIDEWINDOW来显示选中的新视图,或隐藏旧视图。采用这种方法,使对视图操作更加灵活,可以很方便在TabView中添加和删除不同视图。
三、CSheetCtrl标签选择窗口实现TabView
CSheetCtrl不是MFC类库中的类,用它来实现TabView的方法和上一个方法基本相同。在程序员大本营网站的VC编程源代码集的[其它控制]分类中,”ATab-likeSheetCtrl”程序含有该类源代码,但在使用时要将窗口的切换改为视图切换。
1.标签窗口的创建
CSheetCtrl实现的Attach()函数,是它与外部的接口。在CTabSheetCtrl中定义CSheetsWndm_Sheet,初始化过程中,通过调用m_Sheet.Attach(this)将CSheetCtrl创建为CTabSheetCtrl窗口的子窗口。
BOOLCSheetsWnd::Attach(CWnd*pWndParent,COLORREFrgbBackground)
{
//确定了标签窗口的大小和位置
CRectrect=GetRect(pWndParent);
…
BOOLbResult=Create(…,rect,…);
…
returnbResult;
}
CRectCSheetsWnd::GetRect(CWnd*pWndParent)
{
CRectrect;
pWndParent->GetClientRect(rect);
rect.top=rect.bottom-GetSystemMetrics(SM_CYVTHUMB);
returnrect;
}
2.查找所选视图窗口
CSheetCtrl实现了类似于CTabCtrl的功能,如绘制标签窗口、判断用户的选择等。它本身并没有保存任何有关视图的信息,在视图切换时,它通过其父窗口来查找用户所选的视图窗口。
//得到父窗口的第一个的视图子窗口指针函数
CWnd*CSheetsWnd::GetFirstView()
{
m_pViewFind=GetParent()->GetWindow(GW_CHILD);
//m_hWnd存放的是CSheetCtrl标签窗口
//排除CSheetCtrl标签窗口
while(m_pViewFind&&m_pViewFind->m_hWnd==m_hWnd)
m_pViewFind=m_pViewFind->GetWindow(GW_HWNDNEXT);
returnm_pViewFind;
}
//得到下一个视图窗口指针函数
CWnd*CSheetsWnd::GetNextView()
{
if(m_pViewFind)
{
m_pViewFind=m_pViewFind->GetWindow(GW_HWNDNEXT);
while(m_pViewFind&&m_pViewFind->m_hWnd==m_hWnd)
m_pViewFind=m_pViewFind->GetWindow(GW_HWNDNEXT);
returnm_pViewFind;
}
returnNULL;
}按一定的顺序得到所有父窗口(CTabSheetCtrl)的子窗口(CMyView1、CMyView2)指针后,根据每个子窗口的标题所占空间位置,来确定所选择的视图窗口。
//获得第一个视图窗口指针
CWnd*pChild=GetFirstView();
while(pChild)
{
CRectrect(cx,0,0,0);
//rect返回绘制该窗口的标题所需的矩形大小
pDC->DrawText(GetViewTitle(pChild),rect,DEFAULTFORMATDRAWTEXT|DT_CALCRECT);
rect.top=0;
rect.bottom=m_DrawRect.Height();
if((aPointX>cx-LRB)&&(aPointX <=cx+rect.Width()+LRB))//aPointX鼠标位置的横坐标
break;//找到所选视图
//获得下一个视图窗口的指针
pChild=GetNextView();
intnext=rect.Width()+6+LRB;
cx+=next;
}
四、静态分割窗口实现TabView
用静态分割窗口CSplitterWnd实现TabView,其主要的设计思想是通过分割窗口,使用splitter窗口的Pane(0,0)作为切换视的显示区,Pane(0,1)显示类似图3的高级标签窗口CWndTab。CSplitterWnd窗口完成了上面两种方法中CTabCtrlView和CTabSheetView的工作,作为视的窗口和标签窗口的容器。此方法的源代码,在程序员大本营网站也有。
五、结束语
笔者通过分析了多个相关程序的源代码,并且在实际编程过程中,根据需要实现了自己的TabView。在此简要地总结了三种实现TabView的方法,希望对读者的编程能有所帮助。