⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 subject_42018.htm

📁 vc
💻 HTM
字号:
<p>
序号:42018 发表者:李刘江 发表日期:2003-05-31 00:32:33
<br>主题:文档视图高手请进!!!!
<br>内容:&nbsp;&nbsp; 如何在SDI中分别建立两个添满客户区的不同视,并能通过菜单进行切换,急急急?
<br><a href="javascript:history.go(-1)">返回上页</a><br><a href=http://www.copathway.com/cndevforum/>访问论坛</a></p>
<hr size=1>
<blockquote><p>
<font color=red>答案被接受</font><br>回复者:试一试 回复日期:2003-05-31 02:51:36
<br>内容:记不起从哪里盗来的。试过OK<BR><BR><BR><BR><BR>如果用户使用过MFC进行编程,那么就会发现借助于AppWizard基于MFC无论编写SDI(单文档界面)还是编写MDI(多文档界面)都是十分方便的。MDI应用程序目前使用越来越普遍,人们熟悉的Microsoft公司的Office系列产品以及Visual系列产品都是典型的多文档应用程序。这种多文档界面具有多窗口的特点,因而人们可以在一个程序中使用多个子窗口来实现不同数据的浏览查看。如果用户要实现在MDI各个窗口之间针对同一数据进行不同的可视化就是一件比较麻烦的事情。值得庆幸的是,MFC提供的文档-视结构大大简化了这一工作。文档-视结构通过将数据从用户对数据的观察中分离出来,从而方便实现多视,亦即多个视口针对同一数据,如果一个视口中数据发生改变,那么其它相关视口中的内容也会随之发生改变以反映数据的变化。 <BR>SDI和MDI这两种Windows标准应用程序框架并不是总能满足用户的需要,就作者的工作而言,就特别需要一种被称为单文档多视的应用程序,英文可以缩写为SDMV。通过SDMV应用我们可以利用文档类来统一管理应用程序的所有数据,同时需要采用多窗口以多种方式来可视化这些的数据,如棒图,趋势图和参数列表,从而方便用户从不同角度来观察数据。MDI虽然具有多窗口的特点,但是其为多文档,即通常情况下,一个视口对应一个文档,视口+文档便构成一个子窗口。在各个子窗口之间数据相互独立,如果要保持数据同步更新就需要采用特殊的技术了,采用这种方式既费时又费力。通过笔者的实践发现,利用MFC本身提供的多视概念通过适当改造MDI窗口应用程序就可以实现上述SDMV结构。 <BR>所谓SDMV应用程序本质上仍然是一个MDI应用程序,只是在程序中我们人为控制使其只能生成一个文档类,这个文档在第一个视口创建时创建,注意,这里并不需要限制各个视口的创建先后顺序。此后与MDI窗口固有特性不同的是,所有新创建的子窗口都不再创建独立文档,而是把该新视口直接连接到已有的文档对象上,这样就使其成为单文档多视的结构,所有相关数据都存储在文档对象中,一旦文挡中数据发生改变,通过UpdateAllViews()函数通知所有相关视口,各个视口就可以在OnUpdate()中相应数据的变化。这种响应机制如下图所示: <BR><BR>图 1 文档-视结构数据更新机制 <BR>由于MDI本质上并不是为这种单文档多视机制服务的,因而在实际应用时需要解决一些问题。 <BR>1、窗口标题问题 <BR>窗口标题本来不应该成为问题,缺省情况下MDI窗口通过在文档模板中提供的资源ID所提供的对应字符串来确定窗口标题。但是对于SDMV应用,由于各个视口实质上是对应于同一个文挡,因此每个视口都具有相同标题,只不过增加了一个数据用于指示这是第几个视口。如果在各个视口中指明具体的窗口名字,那么由不同的视口启动创建文档产生的窗口标题就不同,这个名字会影响到后继视口。为了作到不同类型的视口如棒图视口和曲线视口具有不同的标题,这就需要一定的技术处理。根据笔者的摸索发现可以采用如下步骤实现: <BR>首先在从标准的MDI子窗口基类CMDIChildWnd派生一个自己的子窗口类,姑且命名为CMyChild,然后在其成员变量中增加一个CString型变量用以存储当前窗口标题: <BR>CString winTitle; <BR>然后在不同的视口创建过程中通过获取父窗口指针按自己的意愿对上述变量进行赋值,程序片段如下: <BR>pChild=(CMyChild*)GetParent(); <BR>pChild-&gt;winTitle="棒图显示窗?quot;; <BR>最后在CMyChild派生类中重载CMDIChildWnd基类中的OnUpdateFrameTitle()函数来强制实现窗口标题的个性化,这一函数在各种类库手册上和联机帮助中都没有,但的确有这样一个具有保护属性的函数用来实现窗口标题的更新操作,这可以从MFC类库的源代码中找到该函数的实现。重载后的源代码如下: <BR>void CMyChild::OnUpdateFrameTitle(BOOL bAddToTitle) <BR>{ <BR>// update our parent window first <BR>GetMDIFrame()-&gt;OnUpdateFrameTitle(bAddToTitle); <BR><BR>if ((GetStyle() &amp; FWS_ADDTOTITLE) == 0) <BR>return; // leave child window alone! <BR><BR>CDocument* pDocument = GetActiveDocument(); <BR>if (bAddToTitle &amp;&amp; pDocument != NULL) <BR>{ <BR>char szOld[256]; <BR>GetWindowText(szOld, sizeof(szOld)); <BR>char szText[256]; <BR><BR>lstrcpy(szText,winTitle); //Modified by author! <BR>if (m_nWindow &gt; 0) <BR>wsprintf(szText + lstrlen(szText), ":%d", m_nWindow); <BR><BR>// set title if changed, but don't remove completely <BR>if (lstrcmp(szText, szOld) != 0) <BR>SetWindowText(szText); <BR>} <BR>} <BR>2、如何创建SDMV应用 <BR>如何创建SDMV应用比较麻烦,下面通过举例来具体说明。该例子假设用户需要建棒图类型和曲线形式的两种视口,假设用户已经利用CView基类派生并且实现了这两个类,分别对应于CMyChart和CMyTraceView两个类。 <BR>1) 在应用类(从CWinApp派生出来的类)的头文件中加入下列变量和函数原型说明: <BR>CMultiDocTemplate* m_pMyTraceTemplate; <BR>CMultiDocTemplate* m_pMyChartTemplate; <BR>int ExitInstance(); <BR>2) 在应用类的InitInstance成员函数中删除对AddDocTemplate函数的调用和OpenFileNew()语句,并且加入如下代码: <BR>m_pMyTraceTemplate = new CMultiDocTemplate( <BR>IDR_MYTRACEVIEW, <BR>RUNTIME_CLASS(CSimuDoc), <BR>RUNTIME_CLASS(CMyChild), // Derived MDI child frame <BR>RUNTIME_CLASS(CMyTraceView)); <BR><BR>m_pMyChartTemplate = new CMultiDocTemplate( <BR>IDR_MYCHART, <BR>RUNTIME_CLASS(CSimuDoc), <BR>RUNTIME_CLASS(CMyChild), // Derived MDI child frame <BR>RUNTIME_CLASS(CMyChart)); <BR>3) 实现ExitInstance()函数,在其中删除所用的两个辅助模板: <BR>int CTestApp::ExitInstance() <BR>{ <BR>if(m_pMyChartTemplate) delete m_pMyChartTemplate; <BR>if(m_pMyTraceTemplate) delete m_pMyTraceTemplate; <BR>return TRUE; <BR>} <BR>4) 在菜单资源中去掉File菜单中的New和Open项,加入New Chart View和New Trace View两项,在对应的菜单命令中实现如下: <BR>void CMainFrame::OnNewMychart() <BR>{ <BR>// TODO: Add your command handler code here <BR>OnNewView(((CSimuApp*)AfxGetApp())-&gt;m_pMyChartTemplate); <BR>} <BR>void CMainFrame::OnNewMyTrace() <BR>{ <BR>// TODO: Add your command handler code here <BR>OnNewView(((CSimuApp*)AfxGetApp())-&gt;m_pMyTraceTemplate); <BR>} <BR>上中OnNewView的实现如下: <BR>BOOL CMainFrame::OnNewView(CMultiDocTemplate* pDocTemplate) <BR>{ <BR>CMDIChildWnd* pActiveChild = MDIGetActive(); <BR>CDocument* pDocument; <BR>if (pActiveChild == NULL || <BR>(pDocument = pActiveChild-&gt;GetActiveDocument()) == NULL) <BR>{ <BR>TRACE0("Now New the specify view\n"); <BR>ASSERT(pDocTemplate != NULL); <BR>ASSERT(pDocTemplate-&gt;IsKindOf(RUNTIME_CLASS(CDocTemplate))); <BR>pDocTemplate-&gt;OpenDocumentFile(NULL); <BR>return TRUE; <BR>} <BR><BR>// otherwise we have a new frame to the same document! <BR>CMultiDocTemplate* pTemplate = pDocTemplate; <BR>ASSERT_VALID(pTemplate); <BR>CFrameWnd* pFrame = pTemplate-&gt;CreateNewFrame(pDocument, pActiveChild); <BR>if (pFrame == NULL) <BR>{ <BR>TRACE0("Warning: failed to create new frame\n"); <BR>return FALSE; // command failed <BR>} <BR>pTemplate-&gt;InitialUpdateFrame(pFrame, pDocument); <BR>return TRUE; <BR>} <BR>OnNewView是整个SDMV应用的核心组成,它的任务是创建一个新的指定类型的视口,它首先判断是否有活动视口存在,文档是否已经创建,正常情况下活动视口存在则表明文档存在,如果不存在则利用所指定的文档模板创建一个新的活动视口,否则则只创建视口,同时将其连接到已存在的文档对象上。 <BR>通过以上步骤就可以实现SDMV应用,在其后的具体应用中利用文档对象的UpdateAllViews()函数和视口的OnUpdate()函数就可以很好的工作了。<BR>
<br>
<a href="javascript:history.go(-1)">返回上页</a><br><a href=http://www.copathway.com/cndevforum/>访问论坛</a></p></blockquote>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -