SplitterWnd的可复用基类

来源:互联网 发布:软件sp版是什么意思 编辑:程序博客网 时间:2024/06/03 03:11

来源: http://www.codeproject.com/KB/splitter/st_splitterwnd.aspx

下载源文件: http://www.codeproject.com/KB/splitter/st_splitterwnd/st_splitterwnd_src.zip

下载Demo: http://www.codeproject.com/KB/splitter/st_splitterwnd/st_splitterwnd_demo.zip

 

介绍

你是否曾经尝试正确的分割Windows窗口,然后加上一个转换视图的方法,更妙的是,你是否还让单独的分隔条铺满整个窗口?然后你还想着让这样的结果在你下次启动程序仍然存在呢?老实讲,我就这样做过,当每次我不得不在旧代码中修改,于是错误和时间频繁出现。

于是,我想静下心来好好的想一个解决方法能解决所有问题的方法,那就是写一个可复用的基类。当然,我从本网站和其它网站找到了很多有用的资料。其中,ShowColumnHideColumn方法借鉴了Oleg Galkin发布在www.codeguru.com上的一篇文章,此外,借助于Caroline EnglebienneAdrian RomanDongik Shin的文章我写出了支持视图转换的方法。

现在,我将再一次分享这些经验。只要你喜欢,你完全可以将这些应用在自己的工程中,但是如果不做照搬过来,我可不能保证不会出现错误甚至崩溃。

本文说介绍的分割窗口基类的方法十分简单,但仍有一些事情需要考虑,否则你会得到CsplitterWnd类中的诸多断言之一。

本文说介绍的基类只适用于静态的窗口切割,并且每次只能切割一个窗口,水平或者垂直。一旦窗口切割完毕,接着还可以在此基础上重复切割,就像上图所示。我将第一个窗口分割成两个面板,左右各一个。接着,我又将左面板分割成上下面板。下面板又被水平地分割位左右面板。

为了实现这样的功能,首先需要将源文件中的ST_splitterwnd.hST_splitterwnd.cpp加到工程中。

接着针对每个要被分割的窗口在CmainFrame中添加相应的ST_splitterWnd成员:

    ST_SplitterWnd* m_pSplitterWnd;
    ST_SplitterWnd* m_pSplitterWnd2;
    ST_SplitterWnd* m_pSplitterWnd3;
    ST_SplitterWnd* m_pSplitterWnd4;

在函数CmainFrame::OnCreateClient中,创造第一个ST_SplitterWnd的对象:

    m_pSplitterWnd = new ST_SplitterWnd();
    m_pSplitterWnd->Create(this,NULL,NULL,pContext,true);

其中Create函数定义如下:

bool Create(CWnd* pParentWnd, // this will do
      CRuntimeClass* pView1, // Add the view for 
                             // the left(or top) pane or NULL
      CRuntimeClass* pView2, // Add the view for
                             // the right(or bottom) pane or NULL
      CCreateContext* pContext, // pass the pContext pointer
                                // from the OnCreateClient
      bool bVertical, // set to true if the window
                      // is split vertically else false
      int nID = AFX_IDW_PANE_FIRST); // this parameter
                                     // does not need redefinition

:如果想要进一步的在分割窗口中进行下次分割,必须将pView1pView2参数中其中一个或两个设为NULL。如果没有这样做,将会出现断言错误。

View1view2是用来将视图类传递到SplitterWnd,就像正常使用CsplitterWnd类一样,也必须使用RUNTIME_CLASS宏进行传递。如:

RUNTIME_CLASS(CSplitterWndTestView3)

使用AddSubDivision方法实现进一步的分割:

   m_pSplitterWnd2 = 
     m_pSplitterWnd->AddSubDivision(LEFT_SIDE,
     RUNTIME_CLASS(CSplitterWndTestView3),NULL,pContext,false);

上面的例子将从水平方向上分割左面板并且在顶面板上填充一个视图,底部的视图通过赋值NULL实现进一步的分割。AddSubDivision函数定义如下:

ST_SplitterWnd* AddSubDivision(int nSide, // use LEFT_SIDE, 
                                              // RIGHT_SIDE, TOP_SIDE
                                              // or BOTTOM_SIDE
        CRuntimeClass* pView1, // Add the view for the
                               // left(or top) pane or NULL
        CRuntimeClass* pView2, // Add the view for the
                               // right(or bottom) pane or NULL
        CCreateContext* pContext, // pass the pContext pointer
                                  // from the OnCreateClient
        bool bVertical); // true for a vertical split,

                         // false for a horizontal split

该函数的用法基本上和Create相同。第一个参数(nSide)用于描述将要添加的分割面板的位置,定义了四个静态常量(LEFT_SIDE, RIGHT_SIDE, TOP_SIDEBOTTOM_SIDE)。最后一个参数将决定是垂直分割(true)还是水平分割(false)AddSubDivison函数返回一个ST_SplitterWnd类型的指针,该指针指向的对象还可以被分割下去:

  m_pSplitterWnd3 = m_pSplitterWnd2->AddSubDivision(BOTTOM_SIDE,
                             NULL,
                             RUNTIME_CLASS(CSplitterWndTestView2),
                             pContext,
                             true);   
   m_pSplitterWnd4 = m_pSplitterWnd3->AddSubDivision(LEFT_SIDE,
                             RUNTIME_CLASS(CSplitterWndTestView4),
                             RUNTIME_CLASS(CSplitterWndTestView5),
                             pContext,

                                        false);

本文说介绍的基类中还有一个特征是在一个面板中进行视图类的转换。为了达到这样的目的,可以使用AddView函数。

:当使用AddView函数时,视图要加入的面板不能包含视图,换句话说,面板必须初始化为NULL,就像再一次分割一样。

  m_nViewNo1 = m_pSplitterWnd->AddView(RIGHT_SIDE,
                         RUNTIME_CLASS(CSplitterWndTestView),
                         pContext);
    m_nViewNo2 = m_pSplitterWnd->AddView(RIGHT_SIDE,
                         RUNTIME_CLASS(CSplitterWndTestView6),
                         pContext);

函数AddView定义如下:

  int AddView(int nSide, // use LEFT_SIDE, RIGHT_SIDE,
                              // TOP_SIDE or BOTTOM_SIDE
          CRuntimeClass * pViewClass,  // Add the view for the 
          CCreateContext* pContext);  // pass the pContext pointer
                                     // from the OnCreateClient

基本上就是上面所说这些工作了。还有三个较为重要的函数:SetInitialStatusSwitchToViewToggleSide

SetInitialStatus用于从注册表中记录一些设置参数,如尺寸,面板位置。

SwitchToView用于同一面板中多个视图的通讯。

ToggleSide隐藏和显示一个面板。

关于作者

姓名:Daniel Zuppinger

简历:1983年来开始从事专业的IT开发。早期的一些工程使用Cobol,接着是PascalModula1CVisual C++1.0C++1986年以后从事咨询工作,1990年以来在瑞士Infobrain工作。目前的研究领域为GSM应用项目管理和软件开发(TAP3)。已婚,有两个女儿。

喜好:Paragliding, OL

职位:CTO

居住地:瑞士

原创粉丝点击