建立静态嵌套式分栏窗口并实现其通信

发表于:2007-07-04来源:作者:点击数: 标签:
紫 瑗 我们在编写程序时,为了加强程序的易用性和获得良好的用户界面,很多时候会用到嵌套式窗口(Splitter window)。由于在含有分栏窗口的程序中,涉及的类将比较多,分栏窗口的各窗格间要进行相互通信,所经的途径也将会比较复杂,稍有不慎,便可能引起程
紫 瑗

  我们在编写程序时,为了加强程序的易用性和获得良好的用户界面,很多时候会用到嵌套式窗口(Splitter window)。由于在含有分栏窗口的程序中,涉及的类将比较多,分栏窗口的各窗格间要进行相互通信,所经的途径也将会比较复杂,稍有不慎,便可能引起程序的错误。本文将介绍一种较安全的实现分栏窗口间相互通信的办法。


  一、 程序原理


  要实现嵌套式分栏窗口,有两种方法,一种为动态创建,一种为静态创建。由于动态创建的代码相对要复杂,所受限制较多(动态窗格不可以超过两行两列),因而本文只介绍静态创建分栏窗口的方法。

  熟悉MFC编程的朋友都知道,MFC程序都有一个主窗口CMainFrame类,这个主窗口可以与程序中的任一类别的窗口类进行通信。于是,我们要在分栏窗口中进行不同类别不同窗格的窗口类通信时,只需要根据当前窗格找到主窗口的指针,再利用该指针便可与其它窗格通信。对于有CDocument类相关联的CView类来说,这种方法尤为重要,因为在有CDocument类相关联的CView类,是不可以安全地与除相关联的CDocument类之外的其它类通信的。所以当要与这样一个类通信时,要先根据主窗口指针得到与之相关联CDocument派生类指针,再用该指针调用其函数进行通信。以上细节,下面程序中均会有体现。


  二、 代码简介及函数说明


  要实现分栏窗口,我们要用到一个MFC类CSplitterWnd类,这个类是专门用于实现分栏窗口的,这个类中较重要并出现于本程序中的函数说明如下:

  1.BOOL CreateStatic(CWnd? pParentWnd, int nRows, int nCol,

  DWORD dwStyle=WS_CHILD|WS_VISIBLE,UINT nID=AFX_IDW_PANE_FIRST);

  功能描述:以pParentWnd为父窗口指针,创建一个含有nRow行、nCol列的静态分栏窗口,并连接到CSplitterWnd类对象中。

  2.virtual BOOL CreateView(int row,int col,CRuntimeClass? pViewClass,SIZE SizeInit,

  CCreateContext? pContext);

  功能描述:把一个CView类连接到由row行col列指定的窗格中。

  3. CWnd? GetPane(int Row,int Col);

  功能描述:返回由Row行、Col列指定窗格的窗口指针。

  4. int IdFormRowCol (int row, int col );

  功能描述:返回row行col列指定的窗格中的ID号。


  三、 程序实现及代码分析


  1.用AppWizard生成一个单文档(SDI)应用程序框架(程序中命名为CUseSplitter)。为了在分栏窗口中显示内容,我们还要另外实现两个CView类。

  (1)用对话框生成器生成一个对话框,设置其style属性为Chile 。用ClassWizard从CFormView类中派生一个类(CSelectView),与对话框关联。

  (2)用ClassWizard从CView类中派生一个新类,命名为CInputView。此时,待连接的View类已准备好。

  2.生成静态分栏窗口,并将刚生成的类连同AppWizard 自动生成的CUseSplitterView类总共三个View派生类连接到分栏窗格中。

  (1)在主窗口的头文件Mainfrm.h中加入如下代码:

  public:

CSplitterWnd m_wndSplitter ;

CSplitterWnd m_wndSplitter2;

  (2)启动ClassWizard,选择主窗口CMainFrame类,重载OnCreateClient函数,修改其代码如下:

  BOOL CMainFrame::OnCreateClient( LPCREATESTRUCT /?lpcs?/,

CCreateContext? pContext)

  {//创建一个静态分栏窗口,分为一行两列

if(m_wndSplitter.CreateStatic(this,1,2)==NULL) return FALSE;

m_wndSplitter.CreateView(0,0,RUNTIME_CLASS(CSelectView),CSize(100,100),

  pContext);

  //将CSelectView连接到0行0列窗格上

if(m_wndSplitter2.CreateStatic(&&m_wndSplitter,2,1,

WS_CHILD|WS_VISIBLE,m_wndSplitter.IdFromRowCol(0, 1))==NULL)

  return FALSE;//将第0行1列再分开2行1列

  //将CInputView类连接到第二个分栏对象的0行0列

m_wndSplitter2.CreateView(0,0,RUNTIME_CLASS(CInputView),CSize(400,300),pContext);

//将CUseSplitterView类连接到第二个分栏对象的1行0列

m_wndSplitter2.CreateView(1,0,pContext->m_pNewViewClass,CSize(400,300),pContext);

return TRUE;

  }

  3.建立窗格间的通信。

  (1)建立CSelectView 和CInputView间的通信。

  确定在CSelectView的实现文件SelectView.cpp中包含如下头文件:

  #include "MainFrm.h"

  #include "CUseSplitterDoc.h"

  #include "InputView.h"

  在第一步生成的对话框中加入一个按钮(程序中为ID_CHECK),用ClassWizard生成其单击响应函数,修改如下:

  void CSelectView::OnCheck()

  {

  //取得主窗口指针。

CMainFrame? MainFrame=(CMainFrame?)this->GetParent()->GetParent();

  //取得窗格row行col列窗口CInputView类的当前指针

CInputView? InputView=(CInputView?)MainFrame->m_wndSplitter2.GetPane(0,0);

InputView->DoSelect(); //实现通信。

  }

  这样,便可实现CSelectView 和CInputView间的通信。当然,在CInputView类中,你应加入响应函数DoSelect()。

  (2)建立CSelectView和CUseSplitterView间的通信。

  同样,在第一步生成的对话框中加入另一个按钮(程序中为ID_INFORMATION),用ClassWizard生成其单击响应函数,修改如下:

  void CSelectView::OnInformation()

  {

CMainFrame? MainFrame=(CMainFrame?)this->GetParent()->GetParent();

CCUseSplitterDoc? Doc=(CCUseSplitterDoc?)MainFrame->GetActiveDocument();

if(Doc!=NULL)

Doc->OnInformation();

  }

接着,在CUseSplitterDoc中新建并实现如下函数:

  void CCUseSplitterDoc::OnInformation()

  {

POSITION pos=GetFirstViewPosition();

CCUseSplitterView? View;

View=(CCUseSplitterView?)GetNextView(pos);

View->DoInformation();

  // 程序实现通信

  }

  同样,只要你在CUseSplitterView中实现一个名为DoInformation()的函数,便可以实现CSelectView和CUseSplitterView之间的通信。

  至此,建立并实现静态分栏窗口间通信的程序已全部完成,运行程序,按下第一栏中的按钮,就可以出现在另一个窗口类中定义的响应消息。 

原文转自:http://www.ltesting.net