前一阵子因为项目需要,了解了一下MFC拆分窗口的实现。这里总结下来,供以后复习和回顾。
(///先摘抄下基本知识)
MFC支持两种类型的拆分窗口:动态和静态。
静态拆分窗口的行列数在拆分窗口被创建时就设置好了,用户不能更改,但是用户可以缩放各行各列。一个静态拆分窗口最多可以包含16行16列。Windows资源管理器即是静态拆分窗口的实例。资源管理器的主窗口在垂直方向上被静态拆分窗口分成了两半。
动态拆分窗口最多可以有两行两列。但他们可以相互拆分和合并。显示在动态拆分窗口中的视图并不是完全独立的:动态拆分窗口在水平方向上被拆分后,两行窗口具有各自独立的垂直滚动条但却公用一个水平滚动条。Visual C++就使用了动态拆分窗口(Window->split)。
选择静态或动态拆分窗口有两个决定因素:
1、是否希望用户能够交互式地修改拆分窗口的行列配置;是,就选用动态拆分窗口。
2、计划在拆分窗口中使用的视图种类。在静态拆分窗口中很容易使用两个以上不同种类的视图,因为你可以在每个窗格中指定所用的视图类型。而动态拆分窗口默认所有视图使用的都是相同视图类。
基于以上了解,以及项目需要,我选用了静态拆分窗口,且是嵌套拆分窗口。
给框架窗口添加静态拆分窗口的过程如下:
1、给框架窗口类(CMainFrame类)添加一个CSplitterWnd数据成员;
2、覆盖框架窗口的OnCreateView在每个静态拆分窗口的窗格中创建视图;
3、使用CSplitterWnd::CreatView在每个静态拆分窗口的窗格中创建视图。(//在MainFrm.cpp中为creatview添加view类头文件,)
以下是几个帖子,对静态拆分窗口进行了详细的介绍。
http://www.vckbase.com/document/viewdoc/?id=192
(///分割线//)
因为我想实现的是先把整个窗口分成一行两列,再把左边一列分成两行一列,再把右边一列分成两行两列。属于嵌套拆分。
按照网上的实现方法总是出现问题,所有语句执行完成后,左边的两行一列总是显示不出来,手动拖动分割线才可以弄出来。于是上网搜索原因及解决方案。遗憾的是,网上给出的例程多是比较简单的拆分。比如先拆成一行两列,再在右半部分分成两行一列;当时几乎没看到在左半部分作文章的。于是,我搜索+尝试了很多遍,终于尝试出来了,以下是我的部分代码,仅供参考。
bool isSingleView;//布尔变量标志拆分是否成功
CSplitterWnd m_wndSplitter;
CSplitterWnd m_wndSplitter_left;
CSplitterWnd m_wndSplitter_right;
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
// TODO: Add your specialized code here and/or call the base class
CRect rect;
GetClientRect(&rect);
if (isSingleView==false)
{
if (!m_wndSplitter.CreateStatic(this,1,2))//先整体分为一行两列
return FALSE;
m_wndSplitter.SetColumnInfo(0,200,0);//这句一定要,否则创建的左分割窗口被继续拆分之后就是显示不出来
if (!m_wndSplitter_left.CreateStatic(&m_wndSplitter,2,1,WS_CHILD|WS_VISIBLE,m_wndSplitter.IdFromRowCol(0,0)))
return FALSE;//再把左边一列拆分成两行
m_wndSplitter_left.CreateView(0,0,RUNTIME_CLASS(C**View),CSize(200,200),pContext);
m_wndSplitter_left.CreateView(1,0,RUNTIME_CLASS(C**View),CSize(200,0),pContext);
if (!m_wndSplitter_right.CreateStatic(&m_wndSplitter,2,2,WS_CHILD|WS_VISIBLE,m_wndSplitter.IdFromRowCol(0,1)))//再把右边一列拆分成两行两列
return FALSE;
m_wndSplitter_right.CreateView(0,0,RUNTIME_CLASS(C**View),CSize((rect.Width()-200)/2,rect.Height()/2),pContext);
m_wndSplitter_right.CreateView(0,1,RUNTIME_CLASS(C**View),CSize(0,rect.Height()/2),pContext);
m_wndSplitter_right.CreateView(1,0,RUNTIME_CLASS(C**View),CSize((rect.Width()-200)/2,0),pContext);
m_wndSplitter_right.CreateView(1,1,RUNTIME_CLASS(C**View),CSize(0,0),pContext);
}
m_bSplitterSuccess=true;
return TRUE;
return CFrameWnd::OnCreateClient(lpcs, pContext);
}
void CMainFrame::OnSize(UINT nType, int cx, int cy)
{
CFrameWnd::OnSize(nType, cx, cy);
if(m_bSplitterSuccess==true) //要加判断语句,否则创建窗口时调用OnSize会导致出错
{
IsSingleView(); //相应的处理函数,随着窗口大小的改变,改变拆分窗口的大小
}
// TODO: Add your message handler code here
}
void CMainFrame::IsSingleView()
{
CRect rect;
GetClientRect(&rect);
if (isSingleView==true)
{
m_wndSplitter.SetRowInfo(0,rect.Height(),0); //设定每行的高度
m_wndSplitter.SetColumnInfo(0,rect.Width(),0); //设定每列的宽度
}
else
{
m_wndSplitter.SetRowInfo(0,rect.Height()/2,1);
m_wndSplitter.SetColumnInfo(0,rect.Width()/2,1);
}
m_wndSplitter.RecalcLayout(); //设置行高和列宽之后重新显示拆分窗口
}
感觉有许多细节部分需要注意,比如SetRowInfo、SetColumnInfo等函数的意义和使用,有时候因为CSize设置的大小不对也可能导致拆分窗口的结果和我们想象的不同。因为总结的时间比较迟了,有很多具体情节记不清了,所以有错误欢迎大家批评指正。以后我会及时总结,那样才会是更全面更准确的。
原文链接:https://blog.youkuaiyun.com/mengzhuanghua/article/details/5954307