




已阅读5页,还剩7页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
本文在介绍了几种标准的单文档与多视结构的VC5.0 MFC实现方法之后,介绍了笔者摸索出的另外两种实用方法,并给出了实现它们的的主要程序框架。一、单文档与多视Windows程序一般分为以下几种风格:多文档、单文档、基于对话框的。Word一类多文档程序和计算器一类基于对话框的程序不在本文介绍之列。单文档又分为单视的和多视的。一般情况下,单文档仅需要单视就够了,如画笔等。但也有一些情况下,单文档需要多视支持,比如同时观察文档的不同部分,同时从不同的角度观察同一文档等。在MFC的框架下,文档对象(CDocument)维持了一个保存其所有视的列表,并提供了增加与删除视的函数,以及当文档内容改变时通知其所有视的方法。通过多文档框架的窗口复制机制和单文档框架的分割窗口机制是实现单文档多视的主要方法。但这些标准方法在有的情况下并不够用,为此笔者摸索出另外两种实用的方法,在实践中使用效果良好。二、三种标准的单文档与多视情况1视对象基于同一视类,每个视位于MDI的一个独立子文档框架中。用户可以通过“窗口新窗口”菜单,为同一文档的视再创建一个窗口,通过新创建的窗口,可以编辑和观察文档的另一部分,同一文档各个视图之间自动实现同步,用户修改一个视的内容,在另外的视中也自动更新。MFC框架通过复制原来的子框架窗口和其中的视来实现上面的功能,并且是完全自动的。2视对象基于同一视类,所有视位于同一文档框架中。分割窗口将单文档窗口的视区分割成几个独立的视,框架从同一视类创建多个视对象。Word的子窗口即属于这种类型。3视对象基于不同的视类,所有的视位于同一文档框架中。多个视共享同一文档框架,但从不同的视类创建,每个视可以为文档提供不同的观察和编辑方法。比如一个视用图形观察文档,而另一个视用文本编辑文档中对象的属性。这种情况也适应于用不同的视来观察文档的不同部分。这种类型的实现方法是通过重载OnCreateClient函数实现。下面的例子实现了图中的分割窗口。BOOL CMainFrame:OnCreateClient( LPCREATESTRUCT,CCreateContext* pContext)RECT rect;/ 先分割为 1X2的形式m_wndSplitter1.CreateStatic(this, 1, 2, WS_CHILD | WS_VISIBLE );m_wndSplitter1.SetColumnInfo(0,300,0); / 设置第一列的宽度/ 将第一列进一步分割为 2X1的形式m_wndSplitter2.CreateStatic( &m_wndSplitter1,2, 1, WS_CHILD | WS_VISIBLE, m_wndSplitter1.IdFromRowCol(0, 0);/ 创建各个视m_wndSplitter1.CreateView(0, 1, RUNTIME_CLASS(CviewView1), CSize(0, 0), pContext);m_wndSplitter2.CreateView(0, 0, RUNTIME_CLASS(CviewView2), CSize(0, 0), pContext);m_wndSplitter2.CreateView(1, 0, RUNTIME_CLASS(CviewView3), CSize(0, 0), pContext);.在实践中,笔者发现这三种方式有时都不适用。比如以下的两种情况:需要在不同的时间分别观察同一文档的不同部分,而文档分割成不同部分的数量较多,这样就不宜用分割窗口来实现,而需要在同一框架中切换不同的视;另一种情况可以说是上面提到的第三种情况和此处第一种情况的组合,即在单文档框架中包含有多个由分割窗口分割的区域,而某(或某些)分割区域中包含有多个不同的视,仅有其中的一个视显示出来。与第三种情况类似,其它分割区域中具有不同的视,但它们同时显示出来。因为在实现方法上有所不同,所以这里分为两种情况来讨论,这也是这篇文章要介绍的重点。三、单文档单框架窗口中的多视下面的例子演示了第一种情况下,具有两个视的简单实现方法。必需考虑如下的问题:非活动的视是否继续连接到文档。当视连接到文档时,它从文档接收OnUpdate通知消息,使其保持与文档内容同步。但这样做将增加计算机的开销,同时也会增加程序开发的任务。另一方法是当非活动的视重新变成活动时,再进行与文档的同步工作。例子中采用后一种方法。BOOL CMainFrame:OnViewChange(UINT nCmdID)CView* pViewAdd;CView* pViewRemove;CDocument* pDoc = GetActiveDocument();UINT nCmdID;nCmdID = LOWORD(GetCurrentMessage()-wParam);if(nCmdID = ID_VIEW_VIEW1) & (m_currentView = 1)return;if(nCmdID = ID_VIEW_VIEW2) & (m_currentView = 2)return;if (nCmdID = ID_VIEW_VIEW2)if (m_pView2 = NULL)m_pView1 = GetActiveView();m_pView2 = new CMyView2;m_pView2-Create(NULL, NULL, AFX_WS_DEFAULT_VIEW,rectDefault, this, AFX_IDW_PANE_FIRST + 1, NULL);pViewAdd = m_pView2;pViewRemove = m_pView1;m_currentView= 2;elsepViewAdd = m_pView1;pViewRemove = m_pView2;m_currentView= 1;/ 将活动视的child id设置为AFX_IDW_PANE_FIRST/ 将其它视设置为AFX_IDW_PANE_FIRST以外的值,/ 这样当调用 CFrameWnd:RecalcLayout重新布局窗口时,/ 才会得到正确的视int nSwitchChildID = pViewAdd-GetDlgCtrlID();pViewAdd-SetDlgCtrlID(AFX_IDW_PANE_FIRST);pViewRemove-SetDlgCtrlID(nSwitchChildID);/ 显示活动视而隐藏非活动视pViewAdd-ShowWindow(SW_SHOW);pViewRemove-ShowWindow(SW_HIDE);/ 将新的活动视连接到文档,并断开原来的视与文档的连接pDoc-AddView(pViewAdd);pDoc-RemoveView(pViewRemove);SetActiveView(pViewAdd);RecalcLayout();四、单文档分割窗口中,某分割区的多视的实现第二种情况下,窗口的分割与标准方法的第3种类似,这里不再重复。下面的函数用于切换某分割(第3种标准界面中,左上区域)区域中的视。这里的实现方法是:先删除原来的视,然后在原分割区域创建一个新的视。void CMainFrame:OnViewView1() ChangeView(RUNTIME_CLASS(CviewView1);ViewingView = ID_VIEW_VIEW1;void CMainFrame:OnViewView2() ChangeView(RUNTIME_CLASS(CviewView2);ViewingView = ID_VIEW_VIEW2;void CMainFrame:OnUpdateViewView1(CCmdUI* pCmdUI) pCmdUI-SetCheck(ViewingView = ID_VIEW_VIEW1);void CMainFrame:OnUpdateViewView2(CCmdUI* pCmdUI) pCmdUI-SetCheck(ViewingView = ID_VIEW_VIEW2);void CMainFrame:ChangeView(CRuntimeClass * pRTClass) / 先删除原来的视m_wndSplitter2.DeleteView(0,0);/ 创建新的视CCreateContext Context;Context.m_pNewViewClass = pRTClass; / 视类Context.m_pCurrentDoc = GetActiveDocument(); / 与文档连接m_wndSplitter2.CreateView(0,0, pRTClass,CSize(0,0),&Context);CView * pView = (CView *)m_wndSplitter2.GetPane(0,0); / 获取分割区域pView-ShowWindow(SW_SHOW);pView-OnInitialUpdate(); SetActiveView(pView);m_wndSplitter2.SetRowInfo(0, 300, 20); / 设置宽度:SetWindowLong(pView-m_hWnd, GWL_ID, AFX_IDW_PANE_FIRST);m_wndSplitter2.RecalcLayout();单文档多视的应用场合很多,可能还有各种不同的需要和实现方法,愿笔者的介绍能对您有所帮助。最近iMaker2000的界面设计所用的是Doc/View结构,涉及到Single Document的多视图带切分的切换。呵呵,光是述说都有点拗口了。VC做界面的确是麻烦啊,不过做好了我相信要比VB或者DELPHI要好,灵活度也会更好。不过就工程角度来说,VC做界面学学也就行了,如果要大规模的做,还是简单快捷的工具比较好。 在网上找了很久相关的代码,最后终于在CodeGure上面找到了一个实现了相应功能的Project。一看时间,晕!98年的,算了,能实现功能就行了。 建立View的过程就不多说了,这里主要说说怎么样切换的。 不带切分的切换比较普遍了,VC技术内幕就有一个详细的代码,我待会会把代码也一起贴出来。 带切分的主要的函数有2个,一个是建立时候的函数,一个是切换的函数,两个基本上很类似,这里分析一下切换的函数: void CMainFrame:OnSwitchView1() / TODO: Add your command handler code here CRect cr; GetClientRect(&cr);/取得客户区的显示区域 CSize paneSize1(3*cr.Width()/4, cr.Height();/设定新view大小 CCreateContext Context;/声明视图文档联系结构并设定其内容 Context.m_pNewViewClass=RUNTIME_CLASS(CSwitchView1); Context.m_pCurrentDoc=(CSwitchApp*)AfxGetApp()-m_pDoc; Context.m_pCurrentFrame=this; Context.m_pNewDocTemplate=Context.m_pCurrentDoc-GetDocTemplate(); Context.m_pLastView=(CView*)m_wndSplitter.GetPane(0,0); m_wndSplitter.DeleteView(0, 1);/删除第1行第2列的View m_wndSplitter.CreateView(0, 1,RUNTIME_CLASS(CSwitchView1),paneSize1, &Context);/动态创建View1 CSwitchView1 *pView=(CSwitchView1*)m_wndSplitter.GetPane(0,1);/得到切分窗口的指针 pView-GetParentFrame()-RecalcLayout();/重绘主窗口 m_wndSplitter.RecalcLayout();/重绘分隔条窗口 pView-OnInitialUpdate();/估计是一些初始化的操作 m_wndSplitter.SetActivePane(0,1);/激活新的分隔区域 不带切分的代码如下: void CMainFrame:SwitchToView(int nForm) /CDocument* pDoc = GetActiveDocument(); CView *pOldActiveView=GetActiveView(); /保存旧视图 CView *pNewActiveView=(CView*)GetDlgItem(nForm); /取得新视图 if(pNewActiveView=NULL) switch(nForm) /这些ID是对话框的标志符,但也可以用其他的标志 case IDD_DIALOG1 : pNewActiveView=(CView*)new TForm; break; case IDD_FORMVIEW : pNewActiveView=(CView*)new TForm2; break; CCreateContext context; /将文挡和视图相连 context.m_pCurrentDoc=pOldActiveView-GetDocument(); pNewActiveView-Create(NULL, NULL, WS_BORDER|WS_CHILD , CFrameWnd:rectDefault, this, nForm, &context); pNewActiveView-OnInitialUpdate(); SetActiveView(pNewActiveView); /改变活动的视图 pNewActiveView-ShowWindow(SW_SHOW); /显示新的视图 pOldActiveView-ShowWindow(SW_HIDE); /隐藏旧的视图 if(pOldActiveView-GetRuntimeClass() =RUNTIME_CLASS(TForm) pOldActiveView-SetDlgCtrlID(IDD_DIALOG1); else if(pOldActiveView-GetRuntimeClass() =RUNTIME_CLASS(TForm2) pOldActiveView-SetDlgCtrlID(IDD_FORMVIEW); pNewActiveView-SetDlgCtrlID(AFX_IDW_PANE_FIRST); delete pOldActiveView; /删除旧视图 RecalcLayout(); /调整框架窗口 比对一下可以看出,带切分的主要是通过m_wndSplitter这样一个成员进行操作,而不带切分的则是直接对整个View进行操作。(因为没有m_wndSplitter啊,呵呵。) 补充一下:刚刚调试了一下代码,有点波折,不过还是顺利通过了,其实代码可以简化很多。 void CMainFrame:OnSwitchView1() m_wndSplitter.DeleteView(1, 0); m_wndSplitter.CreateView(1, 0, RUNTIME_CLASS(TForm2), CSize(0, 0), NULL); m_wndSplitter.RecalcLayout(); 当然,上面这个代码只涉及到了界面的切换,具体的程序中的应用很可能和文档有关,而且需要精确一点的控制,就需要看第一个函数了。注意我的View是纵向的2个,所以参数是1,0。如何在单文档中实现多个视图1.在SDI项目中实现分割多视及获得各视的指针 可先建立两个以CFormView为基类的FormView类CFormViewLeft和CFormViewRight(用资源Dialog 中的Insert. 把基类换成CFormView)在MainFrm.h加入#include 在MainFrm.cpp加入#include FormViewLeft.h#include FormViewRight.h在MainFrm.h中声明CSplitterWnd m_splitterWnd; /声明分隔器对象 CFormViewLeft* m_pFormViewLeft; /声明左边视的指针CFormViewRight* m_pFormViewRight; /声明左边视的指针引入函数CMainFrame:OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext) m_splitterWnd.CreateStatic(this,1,2);/一行两列m_splitterWnd.CreateView(0,0,RUNTIME_CLASS(CFormViewLeft
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年影像科医学影像解读能力评定答案及解析
- 2025年心血管疾病诊断技术应用考核答案及解析
- 2025年药学信息学药物合理应用数据库查询答案及解析
- 2025年胸外科手术操作技巧模拟试题答案及解析
- 民族团结课件边框
- 2025年全科医生常见疾病诊断与处理模拟考试答案及解析
- 品质工作方案模板
- 2025年全科护理实操技能考察答案及解析
- 2025年耳鼻喉科慢性鼻炎药物治疗选择试卷答案及解析
- 2025年神经内科常见病例诊断与治疗模拟考试卷答案及解析
- 村民饮水协议书
- 业余少体校管理办法
- 天津校外培训管理办法
- 小学生晨会课件
- 2025至2030锆英砂行业市场发展分析及发展趋势与投资报告
- DB44∕T 2499-2024 海堤生态化建设技术导则
- 地质灾害诱因成因分析方法-洞察阐释
- 护林防火培训
- 大小便失禁护理指南
- 物业弱电维修课件
- 民宿旅游培训课件
评论
0/150
提交评论