2023年11月29日发(作者:)

VC单⽂档视图分割

该部分主要介绍⼀些基本概念和创建拆分视图的⼀般过程。

MFC⽀持两种类型的拆分窗⼝:静态的和动态的。这⾥只探讨静态拆分,不过⾸先还是要熟悉⼀下这些概念。

静态拆分窗⼝的⾏列数在拆分窗⼝被创建时就设置好了,⽤户不能更改。但是⽤户可以缩放各⾏各列。⼀个静态拆分窗⼝最多可以包含1616列。要找⼀个使⽤了静态拆分

窗⼝的应⽤程序,只要看⼀下windows管理器即可。

动态拆分窗⼝最多可以有两⾏两列,但它们可以相互拆分和合并。Vc就使⽤了动态拆分窗⼝使得可以同时编辑源程序⽂件的两个以上不同的部分。

选择静态或动态拆分的⼀个准则是是否希望⽤户能够交互地修改拆分窗⼝的⾏列配置。 另⼀个决定因素是计划在拆分窗⼝中使⽤的视图种类。在静态拆分窗⼝中很容易使⽤

两个以上不同种类的视图,因为您可以在每个窗格中指定所⽤的视图类型。但是 在动态拆分窗⼝中,MFC管理着视图,除⾮从 CsplitterWnd派⽣⼀个新类并修改拆分窗⼝

的默认操作性能,否则拆分窗⼝中的所有视图使⽤的都是相同的视图类。

静态拆分窗⼝是⽤CsplitterWnd::CreateStatic⽽不是 CsplitterWnd::Create创建,并且由于MFC不会⾃动创建静态拆分窗⼝中显⽰的视图,所以您要亲⾃在CreateStatic返回

之后 创建视图。CsplitterWnd为此提供了名为 CreateView的函数。给框架窗⼝添加静态拆分视图的过程如下:

给框架窗⼝类添加⼀个CsplitterWnd数据成员。

覆盖框架窗⼝的OnCreateClient函数,并调⽤CsplitterWnd::CreateStatic来创建静态拆分视图。

使⽤CsplitterWnd:: CreateView在每个静态拆分窗⼝的窗格中创建视图。

使⽤静态拆分窗⼝的⼀个优点是由于您⾃⼰给窗格添加视图,所以可以控制放⼊视图的种类。

下列中创建的静态拆分窗⼝包含了两种不同的视图:

BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CcreateContext* pContext)

{

if(!m_Static(this, 1, 2) ||

!m_View(0, 0, RUNTIME_CLASS(CtextView), Csize(128, 0), pContext) ||

!m_View(0, 1, RUNTIME_CLASS(CpictureView), Csize(0, 0),pContext) )

return FALSE;

return TRUE;

}

传递给CreateStatic的参数指定了拆分窗⼝的⽗亲以及拆分窗⼝包含的⾏ 列数。对每个窗格调⽤⼀次CreateView。⽤从0开始的⾏列编号来标⽰窗格。在上⾯的代码中,第

⼀次调⽤CreateView在左窗格(00列) 中加⼊类型为CtextView的视图,第⼆次调⽤在右窗格(0 1列)加⼊类型为CpictureView的视图。传递给CreateViewCsize

象指定了窗格的初始尺⼨。在上⾯的代码 中,CtextView窗格的初始宽度为128象素,CpictureView窗格将占据剩余的窗⼝宽度。指定右窗格宽度的值和指定两个窗格⾼度的

值都是 0,这是因为主结构会忽略它们。

下⾯以⼀个单⽂档程序为例,说明静态拆分视图的实现过程:

1 ⾸先建⽴⼀个单⽂档应⽤程序SplitWnd,视图CSplitWndView类型为列表视图。利⽤ CSplitWndView ::OnInitialUpdate初始化列表视图。

2 为该⼯程新增⼀个树型视图类CMyTreeView,并在该类中添加HTREEITEM类型的成员变量 m_hSubTree[2],该成员变量⽤来保存树型视图的⼦树句柄。利⽤

CMyTreeView ::OnInitialUpdate初始化树型视图,为该树型视图添加⼀个树根,两个⼦树,参考代码如下:

HTREEITEM hRoot = GetTreeCtrl().InsertItem(_T("树根"), 。。。, 。。。, TVI_ROOT);

m_hSubTree[0] = GetTreeCtrl().InsertItem(_T("⼦树1"), 。。。, 。。。, hRoot);

m_hSubTree [1] = GetTreeCtrl().InsertItem(_T("⼦树2"), 。。。, 。。。, hRoot);

在框架类中添加⼀个CSplitterWnd 类型的成员变量m_wndSplitter1,并重载OnCreateClient函数来拆分视图,代码如下:

BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)

{

if(!(m_Static(this, 1, 2) ) ||

!(m_View(0, 1, RUNTIME_CLASS(CSplitWndView), CSize(0,0), pContext) ) ||

!(m_View(0, 0, RUNTIME_CLASS(CMyTreeView), CSize(180 ,0), pContext) )

{

return FALSE;

}

return TRUE;

}

如果你设计的程序需要更多的拆分视图,可以再在框架类中添加CSplitterWnd 类型的成员变量m_wndSplitter2,再次利⽤CreateStatic拆分视图,代码如下:

BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)

{

if(!(m_Static(this, 2, 1) ) ||

!(m_View(1, 0, RUNTIME_CLASS(CMyListView), CSize(0,0), pContext) ) ||

!(m_Static(&m_wndSplitter1, 1, 2, WS_CHILD|WS_VISIBLE, m_RowCol(0,0)) ) ||

!(m_View(0, 0, RUNTIME_CLASS(CMyTreeView), CSize(180 ,0), pContext) ) ||

!(m_View(0, 1, RUNTIME_CLASS(CSplitWndView), CSize(0,0), pContext) )

)

{

return FALSE;

}

m_Info(0, 350, 0); //重新设置⾏宽

m_Layout();

return TRUE;

}

现在基本的界⾯就建⽴好了,有关初始化列表视图的代码要根据具体情况来添加。另外,别忘记在框架.cpp中包含视图类的头⽂件。

当你在CMainFrame中加⼊ #include "CSplitWndView.h"可能会报错

error C2143: syntax error : missing ';' before '*'

error C2501: 'CSplitWndDoc' : missing storage-class or type specifiers

error C2501: 'GetDocument' : missing storage-class or type specifiers

因为我要在CChildFrameonCreateClient中创建窗⼝的静态分割。

最后的解决⽅法是:

是在⾃⼰要使⽤的View类的.h⽂件中加⼊下⾯⼀句声明:

class CSplitWndDoc;

为了视类之间的通讯,我们让这些视类共⽤⼀个⽂档类,现在来编写视图之间通讯的代码:

1.在⽂档类中添加int m_nViewType,表⽰要显⽰的类型。当⽤户单击⼦树1”⼦树2”时改变其值。

2.建⽴树型视图通知TVN_SELCHANGED响应函数OnSelchanged,添加如下代码:

CSplitWndDoc* m_pDoc = (CSplitWndDoc*)GetDocument();

HTREEITEM hTmp = GetTreeCtrl().GetSelectedItem(); //得到当前选中的⼦树句柄

//m_pDoc->m_nViewType复位

m_pDoc->m_nViewType = 1000;

if(hTmp == m_hSubTree [0] && m_pDoc)

{

m_pDoc->m_nViewType = 0; //将显⽰类型设置为⼦树1

}

if(hTmp == m_hSubTree [1] && m_pDoc)

{

m_pDoc->m_nViewType = 1; //将显⽰类型设置为⼦树2

}

//在改变⼦树的情况下才刷新CSplitWndView视图

if(hTmp == m_hSubTree [0] || hTmp == m_hSubTree [1] && m_pDoc)

{

//通知视图更新CSplitWndView

m_pDoc->UpdateAllViews(this);

}

3.在CSplitWndView中重载OnUpdate函数,响应UpdateAllViews

CSplitWndDoc* pDoc = GetDocument();

GetListCtrl().DeleteAllItems(); //删除列表视图中的项

switch(pDoc->m_nViewType) //查看视图类型

{

case 0:

//将与⼦树1相关的项添加到列表视图中

break;

case 1:

//将与⼦树2相关的项添加到列表视图中

break;

}