MFC嵌套拆分窗口的实践总结

本文详细介绍了如何在MFC中实现静态拆分窗口,包括选择静态拆分窗口的原因,创建过程以及嵌套拆分的步骤。作者通过实例代码展示了如何将窗口拆分为一行两列,然后对左右两列进行进一步的拆分,解决在实现过程中遇到的问题。同时,强调了在调整窗口大小时需注意的细节,如SetRowInfo和SetColumnInfo函数的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前一阵子因为项目需要,了解了一下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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值