1.4 STLViewer的程序框架

图1-5显示了STLViewer的MFC文档/视图结构框架。STLViewer采用MFC提供的单文档模板,其中包含四个主要的应用程序类:

● 文档类CSTLViewerDoc。

● 视图类CSTLViewerView。

● 主框架类CMainFrame。

● 应用程序类CSTLViewerApp。

它们所对应的源文件分别是:STLViewerDoc.h,STLViewerDoc.cpp,STLViewerView.h,STLViewerView.cpp,MainFrm.h,MainFrm.cpp,STLViewerApp.h,STLViewerApp.cpp。所有本书提及的源程序VC++代码都在随书附带的光盘内。

图1-5 STLViewer的文档/视图结构

下面将对这四个应用程序类的分别加以分析。

1.文档类CSTLViewerDoc

文档类负责管理应用程序的数据。在STLViewer中,CSTLViewerDoc由MFC的文档基类CDocument派生,并插入了存放几何模型的对象m_Part。m_Part由一个自定义的几何模型类CPart定义,用于存储和管理STLViewer应用程序中全部的几何模型。

CSTLViewerDoc的定义如下(详见本书附带光盘内的STLViewerDoc.h文件):

class CSTLViewerDoc : public CDocument
{
protected: // create from serialization only
      CSTLViewerDoc();
      DECLARE_DYNCREATE(CSTLViewerDoc)
// Attributes
public:
      CPart m_Part;()//几何模型对象
// Operations
public:
// Overrides
      // ClassWizard generated virtual function overrides
      //{{AFX_VIRTUAL(CSTLViewerDoc)
      public:
      virtual BOOL OnNewDocument();
      virtual void Serialize(CArchive& ar); //对m_Part进行串行化存储和读取操作
      //}}AFX_VIRTUAL
// Implementation
public:
      virtual ~CSTLViewerDoc();
#ifdef _DEBUG
      virtual void AssertValid() const;
      virtual void Dump(CDumpContext& dc) const;
#endif
protected:
// Generated message map functions
protected:
      //{{AFX_MSG(CSTLViewerDoc)
      afx_msg void OnStlFilein();       //通过读取STL格式文件,创建m_Part的几何模型
      //}}AFX_MSG
      DECLARE_MESSAGE_MAP()
};

对m_Part进行串行化存储和读取操作由CSTLViewerDoc的串行化函数Serialize()实现。用m_Part代表的几何模型可以以二进制文件的形式存储在磁盘上,或从一个磁盘文件中读取出来并创建该对象。而执行函数OnStlFilein()则可通过读取STL格式文件,创建m_Part几何模型的内容。

CPart由一个自行开发的动态链接库GeomKernel.dll输出。关于CPart类的描述,将在本书第6章开发几何内核库时详细介绍。

2.视图类CSTLViewerView

视图类负责文档类中数据的显示,以及负责处理用户与图形窗口之间的交互操作。CSTLViewerView是在CGLView基础上派生的,用于在OpenGL的三维环境下绘制和操作几何模型对象m_Part。通常,应用程序的视图类都是由MFC提供的基类CView派生得来的。但由于CView作为一个视图窗口的基础类,没有直接调用OpenGL绘制三维几何图形的功能,因此在本书开发的CAD图形显示动态链接库glContext.dll中,专门开发了支持OpenGL的视图类CGLView,它由CView类派生,并采用面向对象技术封装了OpenGL的图形绘制功能。CGLView的设计将在以后的章节中详细论述。由于在类CGLView中已经实现了主要的模型显示和操作功能,类CSTLViewerView所承担的任务更多的是接收用户输入信息,并调用CGLView中的相关函数处理用户输入。

CSTLViewerView的定义如下(详见本书附带光盘内的STLViewerView.h文件):

class CSTLViewerView : public CGLView
{
protected: // create from serialization only
      CSTLViewerView();
      DECLARE_DYNCREATE(CSTLViewerView)
//Attributes
public:
      CSTLViewerDoc* GetDocument();
      virtual void RenderScene(COpenGLDC* pDC); //用OpenGL显示m_Part几何模型
//Operations
public:
//Overrides
      // ClassWizard generated virtual function overrides
      //{{AFX_VIRTUAL(CSTLViewerView)
      public:
      virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
      protected:
      //}}AFX_VIRTUAL
//Implementation
public:
      virtual ~CSTLViewerView();
#ifdef _DEBUG
      virtual void AssertValid() const;
      virtual void Dump(CDumpContext& dc) const;
#endif
protected:
// Generated message map functions
protected:
      //{{AFX_MSG(CSTLViewerView)
//}}AFX_MSG
      DECLARE_MESSAGE_MAP()
      virtual BOOL GetBox(double& x0,double& y0,double& z0,double& x1,double& y1,double& z1);       //获取视图中显示模型的最大包围盒
};

如图1-6所示,视图类中的虚拟函数CSTLViewerView::RenderScene() 在基类CGLView的绘图响应函数CGLView::OnDraw() 中被调用,用于执行基于OpenGL的场景绘制,即绘制CSTLViewerDoc::m_Part模型所包含的几何内容。用户可直接在RenderScene()函数中直接或间接调用OpenGL的图形绘制命令,以实现CAD模型的三维空间绘制。

图1-6 在应用程序中重载RenderScene()函数实现OpenGL图形绘制

3.主框架类CMainFrame

主框架类提供了文档界面的主窗口,并创建和管理系统菜单、浮动工具条和状态条等界面对象。在程序STLViewer中,在MFC AppWizard生成的界面基础上进一步增强了用户界面的功能,即在主框架类CMainFrame中插入了一个具有Visual Studio界面风格的浮动窗口对象(图1-7所示界面中左边的包含树型视图的窗口)和一个信息输出框对象(图1-7所示界面中底部的信息输出窗口),分别用于几何模型的浏览操作和提示信息的输出。浮动窗口和信息输出框对象是由对象m_LeftDockBar和m_OutputDockBar对应表示的。在本书第9章将介绍一个用于界面增强的动态库DockTool.dll的开发,该动态库中开发并输出了几个专门用于界面增强的类。对象m_LeftDockBar、m_OutputDockBar分别由DockTool.dll的输出类或输出类的派生类所定义。对象m_LeftDockBar是一个具有浮动特性的窗口,它的功能类似于Visual C++开发环境中的Workspace窗口,可以在主框架内任意浮动,并可以在其中嵌套多个视图,这些视图又可以与文档相关联,即实现文档多视图。m_OutputDockBar也是一个具有浮动特性的窗口,但只可以停靠在主窗口内的上下侧,在其中还嵌套了一个用于文本输出的滚动视图用于系统信息的输出显示。

CMainFrame的主要任务集中在创建并管理上述界面对象。

类CMainFrame的定义如下(详见本书附带光盘内的Mainfrm.h文件):

class CMainFrame : public CFrameWnd
{
      protected: // create from serialization only
      CMainFrame();
      DECLARE_DYNCREATE(CMainFrame)
// Attributes
public:
      CMyLeftDockBar m_LeftDockBar; //可嵌套多个视图的浮动窗口
      CMessageViewDockBar m_OutputDockBar; //提示信息输出浮动窗口
// Operations
public:
// Overrides
      // ClassWizard generated virtual function overrides
      //{{AFX_VIRTUAL(CMainFrame)
      public:
      virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
      //}}AFX_VIRTUAL
// Implementation
public:
          virtual ~CMainFrame();
#ifdef _DEBUG
      virtual void AssertValid() const;
      virtual void Dump(CDumpContext& dc) const;
#endif
protected: // control bar embedded members
      CStatusBar()m_wndStatusBar;
      CToolBar()m_wndToolBar;
      CToolBar m_wndDisplayBar;       //显示操作工具条
// Generated message map functions
protected:
      //{{AFX_MSG(CMainFrame)
      afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
          // NOTE - the ClassWizard will add and remove member functions here.
          //()DO NOT EDIT what you see in these blocks of generated code!
      //}}AFX_MSG
          DECLARE_MESSAGE_MAP()
      void DockControlBarLeftOf(CToolBar* Bar,CToolBar* LeftOf);
};

图1-7 框架类CMainFrame设计与STLViewer的主界面中的窗口对象

4.应用程序类CSTLViewerApp

类CSTLViewerApp负责管理应用程序的主线程,从程序的初始化、运行,直到最后的清除任务。程序STLViewer中,类CSTLViewerApp由CWinApp直接派生:

class CSTLViewerApp : public CWinApp
{
public:
      CSTLViewerApp();
public:
      virtual BOOL InitInstance();       //重载函数,以创建文档/视图结构
      afx_msg void OnAppAbout();
      DECLARE_MESSAGE_MAP()
};

这里需要介绍的是对CWinApp:: InitInstance()函数的重载。InitInstance是CWinApp的基类CWinThread中的一个虚函数,就是“初始化实例”的意思。它在实例创建时首先被调用,应用程序总要重载这个虚函数,进行系统设置、创建运行环境。而且,主窗口、视图窗口、文档对象等一定要在InitInstance()中创建,因为该函数退出后就进入了应用程序主线程的消息循环。

为了形成一个文档/视图结构的应用程序,在应用程序类的CSTLViewerApp::InitInstance()函数重载中,MFC帮助创建了一个单文档模板类对象,并且在文档模板的构造函数中,用系统定义的宏RUNTIME_CLASS创建了文档类CSTLViewerDoc、框架窗口类CMainFrame和视图类CSTLViewerView的对象。在一个应用程序中,可以使用多个模板,这些模板由系统创建的一个链表进行管理。因此,在创建模板之后,还要使用AddDocTemplate()函数把该模板添加到模板链表中。

InitInstance()函数内容通常由MFC的程序向导(AppWizard)自动生成。在客户程序中,可以对该函数作进一步修改,例如给程序增加一个封面、设置主窗口的初始状态等。

BOOL CSTLViewerApp::InitInstance()
{
……
    //创建应用程序的文档/视图模板
    CSingleDocTemplate* pDocTemplate;
    pDocTemplate = new CSingleDocTemplate(()/创建一个单文档模板
        IDR_MAINFRAME,
        RUNTIME_CLASS(CSTLViewerDoc),
        RUNTIME_CLASS(CMainFrame),
        RUNTIME_CLASS(CSTLViewerView));
    // 将该文档视图模板添加到模板链表中
    AddDocTemplate(pDocTemplate);
    …….
    // 显示应用程序的主框架窗口
    // 设置主窗口的初始状态,使用SW_SHOWMAXIMIZED参数,以实现窗口满屏幕显示
    m_pMainWnd->ShowWindow(SW_SHOWMAXIMIZED);
    m_pMainWnd->UpdateWindow();
    return TRUE;
}