VC++ 6.0中实现三叉切分窗口与多视图 [转]

摘要:
静态拆分窗口最多支持16行16列窗格,不同的窗格通常使用不同的视图类。2、 该示例以单文档SDI应用程序为例,并在框架客户机区域中实现了一个三叉分割窗口,每个窗格使用不同的视图。实施步骤:1。使用VC++6.0的AppWizard创建一个名为Test的文档SDI应用程序。7.在视图窗口类CTestView_WndSplitter2中声明CsplitterWnd类的成员变量m,用于第二次分段。

一、引用

  当用户需要同时对文当的不同部分进行编辑时,常常会用到切分窗口;这些窗口可以都是相同的视,或者一个窗口为列表视,而另一个为树型视图。应用程序框架有多种方式来表示多视图,切分窗口是其中的方式之一。

  切分窗口分为动态切分窗口和静态切分窗口,它们都是由CsplitterWnd类(MFC类库)来实现的,在这两种表示方式中,创建同一视图类的对象是比较容易的(Cview),而在同一应用程序使用两个或更多的视图类(如:ClistView、CtreeView等),相对来说则要困难一些。

  动态切分功能多应用在编辑文本类的软件中,在实际的开发中,我们经常要用到的是静态切分功能。静态切分窗口是指在窗口创建时,切分窗口的窗格就已经创建好了,且窗格的数量和顺序不会改变,窗格为一个分隔条所分隔,用户可以拖动分隔条调整相应窗格的大小。静态切分窗口最多支持16行´16列的窗格,而且不同的窗格往往使用不同的视图类。本文主要阐述静态切分窗口。

  

二、实例

  以单文档SDI应用程序为例,在框架客户区实现三叉切分窗口,且每个窗格使用不同的视图 。

  实现步骤:

  1、 利用VC++6.0 的AppWizard创建一个单文档SDI应用程序,项目名为Test。

  2、 使用New Class对话框添加新的视图类:

  CinfoView 基类为列表视图类ClistView

  CLineView 基类为表单视图类CFormView

  CMyEditView 基类为编辑视图类CEditView

  要点:在添加ClineView之前,需要先创建一个对话模板资源,ID为IDD_FORMVIEW,

  3、 在框架窗口类CMainFrame中声明一个CsplitterWnd类的成员变量m_wndSplitter1,用于第一次切分。

  4、 使用ClassWizard为框架窗口类添加OnCreateClient函数。

  注意:OnCreateClient函数的调用在OnCreate函数之后,在构造视图对象和产生视图窗口之前。

  5、 在OnCreateClient函数中调用CsplitterWnd::CreateStatic,产生静态切分。该函数的原形如下:

BOOL CreateStatic( CWnd* pParentWnd, int nRows, int nCols, DWORD dwStyle =WS_CHILD | WS_VISIBLE, UINT nID =AFX_IDW_PANE_FIRST );

  函数有5个参数,意义如下:

  ● pParentWnd:切分窗口的父窗口指针

  ● nRows:水平方向分隔窗口的数目

  ● nCols:垂直方向分隔窗口的数目

  ● dwStyle:切分窗口的风格

  ● nID:子窗口的ID值,默认为系统定义的AFX_IDW_PANE_FIRST

  返回值:如果创建成功,返回非零值(TRUE),否则返回0(FALSE)。

  m_wndSplitter1.CreateStatic(this, 2,1); // 切分为行列

  6、 使用CreateView产生每个视图窗口

virtual BOOL CreateView( int row, int col, CRuntimeClass* pViewClass, SIZE sizeInit, CCreateContext* pContext );

  函数有5个参数,意义如下:

  ● row:窗格的行标,从0开始

  ● col:窗格的列标,从0开始

  ● pViewClass:视图的执行期类CRuntimeClass指针,可以用宏RUNTIME_CLASS获得

  ● sizeInit:一个SIZE(或者CSize)类型的数据,指定窗格的初始大小

  ● pContext:一般是由父窗口传递过来,包含窗口的创建信息

  返回值:如果创建成功,返回非零值(TRUE),否则返回0(FALSE)。

  OnCreateClient函数的全部代码:

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

          CRect rect;

              GetClientRect(&rect);

              //产生第一次静态切分
              m_wndSplitter1.CreateStatic(this, //父窗口指针

                      2, // 切分的行数

                        1); // 切分的列数

                 //为第一个窗格产生视图

                 m_wndSplitter1.CreateView(0,0, // 窗格的行、列序数

                        RUNTIME_CLASS(CTestView),//视图类

                          CSize(rect.Width(),rect.Height()-rect.Height()/5),//初始化大小

                            pContext);//父窗口的创建参数

                   //为第二个窗格产生视图

                   m_wndSplitter1.CreateView(1,0,

                          RUNTIME_CLASS(CMyEditView),

                            CSize(rect.Width(),rect.Height()/5),

                               pContext);

                      return TRUE;//不再调用基类的OnCreateClient函数

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

   }

  在这里需注意3点:

  ① 必须为每个静态切分窗格创建视图窗口,不能漏掉一个;

  ② 必须包含相应的类的头文件,在MainFrm.cpp文件的开始包含一下头文件:

  #include "TestView.h"
  #include "MyEditView.h"

  ③产生静态切分后,就不能调用默认的基类的OnCreateClient函数。

  7、 在视图窗口类CTestView中声明一个CsplitterWnd类的成员变量m_wndSplitter2,用于第二次切分。

  8、 使用ClassWizard为视图窗口类CTestView添加OnCreate函数,在该函数中调用CreateStatic函数和CreateView函数,类似CMainFrame::OnCreateClient函数中的调用

  代码如下:

 int CTestView::OnCreate(LPCREATESTRUCT lpCreateStruct)
   {

          if (CView::OnCreate(lpCreateStruct) == -1)
                 return -1;

            // TODO: Add your specialized creation code here
            CRect rect;
              GetClientRect(&rect);

                 //获得窗口的创建信息指针
                 CCreateContext *pContext = (CCreateContext*) lpCreateStruct->lpCreateParams;

                   //产生二次静态切分
                   m_wndSplitter2.CreateStatic(this,1, 2);

                      //为第一个窗格产生视图
                      m_wndSplitter2.CreateView(0,0,// 窗格的行、列序数

                            RUNTIME_CLASS(CLineView),//视图类

                               CSize(rect.Width()/4,rect.Height()),//初始化大小

                                 pContext);//父窗口的创建参数

                        //为第二个窗格产生视图
                        m_wndSplitter2.CreateView(0,1,

                               RUNTIME_CLASS(CInfoView),

                                 CSize(1,1),

                                    pContext);

                          return 0;

   }

  注意:二次切分的父窗口是第一次切分的第一个窗格,其视图类是CTestView

  9、使用ClassWizard为视图窗口类CTestView添加OnSize函数,在该函数中调用子函数

  SwitchView(),子函数的代码如下:

void CTestView::SwitchView()
{

  CRect rect;

  GetClientRect(&rect);

  int cx = rect.Width();

  int cy = rect.Height();

  m_wndSplitter2.MoveWindow(-2,-2,cx,cy+3);

  m_wndSplitter2.SetColumnInfo(0, cx/4,0);

  m_wndSplitter2.SetColumnInfo(1, cx-cx/4, 0);

  m_wndSplitter2.RecalcLayout();

}

  该子函数主要用于设置二次切分后的各列信息,通过CSplitterWnd::SetColumnInfo函数实现,原型为:void SetColumnInfo( int col, int cxIdeal, int cxMin );

  由3 个参数,意义如下:

  ● col:切分窗口的列标识

  ● cxIdeal:列的实际宽度,单位为像素

  ● cxMin:列的最小宽度,单位为像素

本示例的运行结果如下:

10、因为每个CView派生类都已经继承了GetDocument()函数,因此只要在调用时直接调用无需再在其中声明GetDocument()函数了,调用后再进行类型强制转换应该就可以了。比方,在TestView.h中注释掉

// Attributes
// CTestDoc* GetDocument();

在TestView.cpp中注释掉

//CTestDoc* CTestView::GetDocument() // non-debug version is inline
//{
   //ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CTestDoc)));
   //return (CTestDoc*)m_pDocument;
//}

并在OnDraw中试用如下代码

void CTestView::OnDraw(CDC* pDC)
{
     CTestDoc* pDoc =(CTestDoc*)CTestView:: GetDocument();
     ASSERT_VALID(pDoc);
// TODO: add draw code for native data here }

  三、总结

  切分窗口的形式和每个窗格所使用的视图类可以根据实际需要来确定,以满足程序的不同应用。本示例使用了三叉切分,视图类使用了列表视图类CListView、表单视图类CFormView、编辑视图类CEditView,在VC++6.0下调试通过。

  三叉切分的方法并不唯一,本文实例是我在实际开发中总结的一种方法,读者可以通过本例举一反三,掌握切分窗口与多视图相结合的精髓所在。

 一、关于CSplitterWnd类

1、用来创建动态切分窗口

BOOL   Create(CWnd*   pParentWnd,int   nMaxRows,int   nMaxCols,SIZE   sizeMin,CCreateContext*   pContext,DWORD  dwStyle,UINT   nID);

2、用来创建静态切分窗口

BOOL   CreateStatic(CWnd*   pParentWnd,int   nRows,int   nCols,DWORD   dwStyle,UINT   nID)  

3、为静态切分的窗口的网格填充视图

BOOL   CreateView   (int   row,int   col,CruntimeClass*   pViewClass,SIZE   sizeinit,CcreateContext*   pContext);  

4、参数说明

pParentWnd   切分窗口的父框架窗口。

        nMaxRows,nMaxCols是创建的最大的列数和行数。  

        sizeMin是窗格的现实大小。  

        pContext   大多数情况下传给父窗口。  

        nID是字窗口的ID号.  

二、创建嵌套分割窗口

1、动态分割窗口

动态分割窗口使用Create方法,例:m_wndSplitter.Create(this,2,2,CSize(100,100),pContext);   但是一般不使用动态分割,不实用

2、静态分割窗口(适用于SDI、MDI程序)

1)创建单文档ww,生成的视类为CWwView,从CFormView继承;再增加个视类或者从视类继承而来的派生类CView2、CView3。

2)在框架类CMainFrame的.cpp文件中加入头文件,并在CWwView类定义前加上  class   CWwDoc;

#include   "view2.h "
#include   "view3.h "

#include   "wwView.h " //注意这里,必须在CWwView类定义前加上class   CWwDoc;否则编译条错误

3)在框架类CMainFrame中增加成员:  

    CSplitterWnd   m_wndSplitter1;
    CSplitterWnd   m_wndSplitter2;

4)利用ClassWizard重载CMainFrame::OnCreateClient()函数

//--------------------------------------------------
BOOL   CMainFrame::OnCreateClient(LPCREATESTRUCT   lpcs,   CCreateContext*   pContext)  
{
     //创建一个行列
     m_wndSplitter1.CreateStatic(this,1,2);

     //将CWwView连接到行列窗格上
     m_wndSplitter1.CreateView(0,0,RUNTIME_CLASS(CWwView),CSize(100,100),pContext);

     //将窗口右边再分开行列
     m_wndSplitter2.CreateStatic(&m_wndSplitter1,2,1,WS_CHILD|WS_VISIBLE,   m_wndSplitter1.IdFromRowCol(0,   1));

     m_wndSplitter2.CreateView(0,0,RUNTIME_CLASS(CView2),CSize(100,100),pContext);

     m_wndSplitter2.CreateView(1,0,RUNTIME_CLASS(CView3),CSize(100,100),pContext);


     return   TRUE;
}
  //-------------------------------------------------

 注意:

①   必须为每个静态切分窗格创建视图窗口,不能漏掉一个;

②   如果从一个CformView类继承的视类,此对话框要作如下设置

style=Child

Border=None

Visible=不选中

③   若在CWwView窗口上放入一TreeCtrl,为了在改变窗口时随窗口大小而改变(类似CB中的居中),可以在CWwView类的WM_SIZE中添加代码如下:

//-------------------------------------------------
void   CWwView::OnSize(UINT nType, int cx, int cy)  
{
     CFormView::OnSize(nType,   cx,   cy);

     //   TODO:   Add   your   message   handler   code   here
     if   (GetSafeHwnd())
     {
         CRect   rect;
         GetClientRect(&rect);

         if   (m_TreeCtrl.GetSafeHwnd())
              m_TreeCtrl.MoveWindow(&rect);
     }
}
//------------------------------------------------

//在WM_ONINITALUPDATE消息中,添加初始化数据
void   CWwView::OnInitialUpdate()
{
     CFormView::OnInitialUpdate();

     GetParentFrame()-> RecalcLayout();

     ResizeParentToFit();

     //上面的代码不用管,是啥就是啥,
     m_TreeCtrl.InsertItem( "ListCtrl View ",1, 1);

     m_TreeCtrl.InsertItem( "EditCtrl View ",2, 2);

}

三、实现各个分割区域的通信

点击Button1按钮,在CView2中显示文字

1、在CWwView的.cpp文件中加入:

#include   "view2.h "
#include   "MainFrm.h "

2、添加按钮代码:

//-------------------------------------------------
void   CWwView::OnButton1()  
{
     //得到一SplitterView的指针
     CView2   *pView=(CView2*)(((CMainFrame*)AfxGetMainWnd())-> m_wndSplitter2.GetPane(0,0));

     //定义View的DC
     CClientDC   dc(pView);

     dc.MoveTo(10,10);

     dc.LineTo(10,100);

     dc.TextOut(10,10, "m_wndSplitter2的行列就是CView2 ");  
}
//-------------------------------------------------

转自:http://www.cppblog.com/Lee7/archive/2008/12/22/70036.html

免责声明:文章转载自《VC++ 6.0中实现三叉切分窗口与多视图 [转]》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Linux命令之basename 命令Android数据库ORMlite框架04下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Qt跨线程调用错误解析及解决办法

错误提示:Error: Cannot create children for a parent that is in a different thread. 错误案例分析 新建SerialLink子线程,继承QThread,并重写它的run(),调用 start()函数时自动调用重载的run()函数。在主线程中创建SerialLink类的对象。 串口_po...

Windows消息机制详解

消息是指什么? 消息系统对于一个win32程序来说十分重要,它是一个程序运行的动力源泉。一个消息,是系统定义的一个32位的值,他唯一的定义了一个事件,向 Windows发出一个通知,告诉应用程序某个事情发生了。例如,单击鼠标、改变窗口尺寸、按下键盘上的一个键都会使Windows发送一个消息给应用程序。 消息本身是作为一个记录传递给应用程序的,这个记录中包含...

AVR单片机教程——走向高层

本文隶属于AVR单片机教程系列。   在系列教程的最后一篇中,我将向你推荐3个可以深造的方向:C++、事件驱动、RTOS。掌握这些技术可以帮助你更快、更好地开发更大的项目。 本文涉及到许多概念性的内容,如果你有不同意见,欢迎讨论。 关于高层 这一篇教程叫作“走向高层”。什么是高层? 我认为,如果寥寥几行代码就能实现一个复杂功能,或者一行代码可以对应到几百句...

ANDROID窗体管理服务实现机制和架构分析

 一、功能     窗体管理是ANDROID框架一个重要部分,主要包含例如以下功能:    (1)Z-ordered的维护   (2)窗体的创建、销毁   (3)窗体的绘制、布局    (4)Token管理,AppToken    (5)活动窗体管理(FocusWindow)    (6)活动应用管理(FocusAPP)    (7)输入法管理  ...

网络socket编程实现并发服务器——多线程编程

一、多线程简介1、什么是线程?       线程在操作系统原理中是这样描述的:线程是进程的一条执行路径。线程在Unix系统下,通常被称为轻量级的进程,线程虽然不是进程,但却可以看作是Unix进程的表亲,所有的线程都是在同一进程空间运行,这也意味着多条线程将共享该进程中的全部系统资源,如虚拟地址空间,文件描述符和信号处理等等。但同一进程中的多个线程有各自的调...

手写Redux-Saga源码

上一篇文章我们分析了Redux-Thunk的源码,可以看到他的代码非常简单,只是让dispatch可以处理函数类型的action,其作者也承认对于复杂场景,Redux-Thunk并不适用,还推荐了Redux-Saga来处理复杂副作用。本文要讲的就是Redux-Saga,这个也是我在实际工作中使用最多的Redux异步解决方案。Redux-Saga比Redux...