用CSplitterWnd类分割窗体

转载 2013年12月04日 11:16:26

VC++6.0使用CSplitterWnd类分割窗体,拆分窗体

晚上一个QQ技术群中的人提出了一个比较尖锐的问题,其尖锐性并不是在于难度,而是复杂度,分割窗体,也叫拆分窗体,这个问题还是值得仔细去研究一番的,下面切入正题。因为比较复杂,所以这个问题我会讲的很细致,基本是带着做下来。

我们在使用WINDOWS的资源管理器的时候都会注意到,他是由左右两部分组成,这就是分割窗体,那么现在我们就来给大家讲一下如何拆分窗体,而且是想怎么拆就怎么拆。以上图的三分窗体为例。(三分会用了,多分就会了)。

多说一句,为了更加直观的体现出分割窗体,我所举的图例当中单文档的菜单栏和工具栏被去掉了,具体方法参见我的另一篇文章《[原创]VC++6.0去掉单文档中的菜单,工具栏,状态栏》。

首先,我们需要定义一个自己的类,继承于CSplitterWnd类,至于为什么不直接使用,而要自己定义,继承呢?现在我先不回答,到后面就清楚了。

第一步:打开Visual C++ 6.0,文件—>新建,选择MFC AppWizard(exe),输入工程名test,点确定,然后选择单文档点下一步,第二,第三,第四,第五都点下一步,第六步的时候让我选择每个类的基类,我们把CTestView类的基类改为CFormView,点完成。

第二步:新建一个类,类的类型选择Generic Class,填写名称为CMySplitter,基类我们填CSplitterWnd,点击确定。这个时候我们有可能会遇到一个问题(之所以我说有可能是因为这种情况有时不会发生),那就是当我们点击确定之后有时会弹出一个对话框,说找不到CSplitterWnd.h文件,这个时候我们点确定即可。因为,MFC的Classwizard不支持继承CSplitter类。但是,我们这里选择的是Generic Class,而不是MFC,所以可以继承,忽略掉那个提醒即可,不明白原因不要紧,只要记得如果弹出对话框,只要点确定即可。

第三步:在CMainFrame类的头文件最顶部加上#include "MySplitter.h",再在CMainFrame类中声明两个public的CMySplitter型的成员变量,如下:

public:
CMySplitter wndSplitter_horizontal;//水平分隔条
CMySplitter wndSplitter_erect;//竖直分隔条

第四步:打开资源视图,新建一个对话框,填写ID为IDD_MONITORTOP_FORM,新建一个类,类的类型选择MFC Class,填写名称为CMonitorTopView,基类我们填CFormView,对话框ID我们填写IDD_MONITORTOP_FORM,这样我们就新建了一个以CFormView为基类的视图类CMonitorTopView。类似的,我们再新建另外一个对话框,ID为IDD_MONITORRIGHT_FORM,以此再建立一个以CFormView为基类的视图类CMonitorRightView。

第五步:重载CMainFrame类的OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)方法。加入代码,具体如下:

BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext) 
{
// TODO: Add your specialized code here and/or call the base class

//创建一个静态分栏窗口,分为2行1列 
if(wndSplitter_horizontal.CreateStatic(this,2,1)==NULL) 
return FALSE;

   //将CMonitorTopView视图连接到0行0列窗格上
   wndSplitter_horizontal.CreateView(0,0,RUNTIME_CLASS(CMonitorTopView),CSize(50,50),pContext);
   
  
    //将第1行0列再分开1行2列
    if(wndSplitter_erect.CreateStatic(&wndSplitter_horizontal,1,2,WS_CHILD|WS_VISIBLE, wndSplitter_horizontal.IdFromRowCol(1, 0))==NULL)
    
    return FALSE; 
   
     //将CMonitorView类连接到第二个分栏对象的0行0列
     wndSplitter_erect.CreateView(0,0,RUNTIME_CLASS(CMonitorView),CSize(220,220),pContext);
     
     //将CMonitorRightView类连接到第二个分栏对象的0行1列
     wndSplitter_erect.CreateView(0,1,RUNTIME_CLASS(CMonitorRightView),CSize(220,220),pContext); 
    
      return TRUE;


//return CFrameWnd::OnCreateClient(lpcs, pContext);
}

第六步:其实,截止到第五步完,我们运行程序就可以出现我图例所实现的样子了,但是现在我们来补充一下改变分隔条的特征,好了,现在你应该知道为什么我们要自己定义一个类,继承自CSplitterWnd了吧,因为我们要修改它的特征,例如改变分隔条的宽度,改变分隔条的颜色,固定分隔条(不让别人拖动)等等。

1、改变分隔条的宽度:在CMySplitter类的构造函数中加入代码,具体如下:

CMySplitter::CMySplitter()
{
m_cxSplitter = 10;    //must >=4 ,拖动时横向拖动条的宽度
m_cySplitter = 25;     //must >=4 ,拖动时竖向拖动条的宽度
m_cxBorderShare = 0; //按下鼠标时横向拖动条的偏移量
m_cyBorderShare = 0; //按下鼠标时竖向拖动条的偏移量
m_cxSplitterGap= 5; //静止时横向拖动条的宽度   
m_cySplitterGap= 5; //静止时横向拖动条的宽度

}

2、固定分隔条(不让别人拖动):锁定切分条的最简单的方法莫过于不让CSplitterWnd类来处理WM_LBUTTONDOWN,WM_MOUSEMOVE,WM_SETCURSOR消息,而是将这些消息交给CWnd窗口进行处理,从而屏蔽掉这些消息。现在我们打开CMySplitter类的头文件,我们手动的添加一些东西(为什么要手动呢?因为,我们选择的是Generic Class),好了,我们来看一下都加入了哪些代码:

class CMySplitter : public CSplitterWnd 
{
public:
CMySplitter();
virtual ~CMySplitter();

//以固定分隔条加入的代码

DECLARE_DYNCREATE(CMySplitter)
  
protected:
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);


DECLARE_MESSAGE_MAP()

//以上是固定分隔条加入的代码
};

我们仔细的看一下在DECLARE_DYNCREATE(CMySplitter)和DECLARE_MESSAGE_MAP()之间是消息处理的声明,告诉计算机,我们重载了这三个消息处理函数。现在我们在打开CMySplitter类的.cpp文件,在构造函数CMySplitter::CMySplitter()上面加入如下代码:

IMPLEMENT_DYNCREATE(CMySplitter, CSplitterWnd)

BEGIN_MESSAGE_MAP(CMySplitter, CSplitterWnd)
ON_WM_LBUTTONDOWN()
ON_WM_SETCURSOR()
ON_WM_MOUSEMOVE()
END_MESSAGE_MAP()

在程序结尾添加下面的代码:

void CMySplitter::OnLButtonDown(UINT nFlags, CPoint point)
{     
    // 直接返回,不处理
return;
}

BOOL CMySplitter::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{   
    // 当光标进入分割窗口时,不允许改变样子,不处理
return FALSE;
}

void CMySplitter::OnMouseMove(UINT nFlags, CPoint point)
{       

     //将CSplitter类的处理改为由CWnd处理
      //CSplitterWnd::OnMouseMove(nFlags, point); 
    CWnd::OnMouseMove(nFlags, point);
}

好了,这样我们就实现了分隔条的固定。这一步是比较有难度的,因为我们要自己写一些消息处理代码。

最后我想大家都会发现一个问题,那就是,你运行出来的单文档程序的三个分割窗口上会出现滚动条,其原因是因为CFormView所基于的对话框模板比分割窗口要大,所以,会出现滚动条,那么我们适当的调整资源中的对话框模板的大小,使之比分割窗口小一点点,这时要注意,如果太小的话,整个单文档框架会缩小,切忌切忌,只要调整使之小一点点即可。

总结一下,分割窗体的重点在于要分析清楚分割顺序,各个子视图的位置。分割窗体,复杂但不难。

C++类和接口的设计原则探讨

  • 2013年08月02日 10:49
  • 3KB
  • 下载

C#里WinForm开发中如何实现控件随窗体大小的改变而自动适应其改变

原文地址:http://01258.blog.51cto.com/2229941/565420 在设计可供用户调整大小的窗体时,如何实现该窗体上的控件也应能正确地随窗体的改变而自动调整大小并且能...

SenchaArchitect-2.0.0.000442

  • 2012年08月21日 09:07
  • 28.81MB
  • 下载

Laravel入门实战之二(CentOS6部署Nginx+Laravel线上运行环境)

安装centos的EPEL的第三方拓展程序包的源:vim /etc/yum.repos.d/epel.repo# [epel] name=Extra Packages for Enterprise...

定时提醒器-免费软件网

  • 2013年09月03日 19:50
  • 6.52MB
  • 下载

CParallelPort

  • 2011年11月22日 22:44
  • 1.58MB
  • 下载

安卓用WebView加载百度首页

要想加载网页首页,可以用WebView来实现。WebView(网络视图)能加载显示网页,我们可用它来做浏览器加载网页,下面前天用WebView实现网页加载的方法。 WebView使用了WebKit渲染...
  • wu_wxc
  • wu_wxc
  • 2015年07月12日 00:29
  • 3545

Google C++ 风格指南 - 中文版

  • 2013年10月23日 21:40
  • 192KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:用CSplitterWnd类分割窗体
举报原因:
原因补充:

(最多只允许输入30个字)