注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

还东国的博客

行之苟有恒,久久自芬芳

 
 
 

日志

 
 

重读深入浅出MFC(4)-一个文档对应多个视  

2011-07-14 15:13:23|  分类: C++(VC)编程 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

说明一下,这下面的几个方法多是从网上找的,谢谢大家,其中分割视图对应多视没有总结,大家可以去搜索

,这个东西一定要细心,任何一点点儿小的设置错误,就达不到目的了。
一、单文档中一个文档对应多个视图的方法
1、创建新的视图,并调用切换函数
void CTestSingleDocDoc::OnFileOpen()
{
 // TODO: Add your command handler code here
 CMyEditView * m_pView1 = new CMyEditView();
 if (m_pView1)
 {
  // create the new view
  m_pView1->Create(NULL, NULL, AFX_WS_DEFAULT_VIEW, CFrameWnd::rectDefault,
   AfxGetMainWnd(), AFX_IDW_PANE_FIRST+1, NULL);
  SwitchToView(m_pView1);
 }
}
需要注意的是,与下面的多文档不同,这里的创建因为是单文档程序,所以只有一个主框架,而且他的视

图ID必须要递增,即AfxGetMainWnd(), AFX_IDW_PANE_FIRST+1这两个参数,和后面的多文档的方法里对

比你会发现他们有什么不同。
2、具体的操作函数
CView* CTestSingleDocDoc::SwitchToView ( CView* pNewView )
{
   CFrameWnd* pMainWnd = (CFrameWnd*)AfxGetMainWnd();
   CView* pOldActiveView = pMainWnd->GetActiveView();
   ASSERT(pOldActiveView != NULL);
   ASSERT_VALID(pOldActiveView);
   ASSERT(pOldActiveView->GetDocument() == this); // must be attached to us


   /* Set the child window ID of the active view to AFX_IDW_PANE_FIRST.
      This is necessary so that CFrameWnd::RecalcLayout will allocate
      this "first pane" to that portion of the frame window's client
      area not allocated to control bars.  Set the child ID of
      the previously active view to some other ID.
   */

   ::SetWindowLong(pOldActiveView->m_hWnd, GWL_ID, 0);
   ::SetWindowLong(pNewView->m_hWnd, GWL_ID, AFX_IDW_PANE_FIRST);

   // Show the newly active view and hide the inactive view.

   pNewView->ShowWindow(SW_SHOW);
   pOldActiveView->ShowWindow(SW_HIDE);

   // Connect the newly active view to the document,

   // and disconnect the inactive view

   AddView(pNewView);
   RemoveView(pOldActiveView);
   pMainWnd->SetActiveView(pNewView);
   pMainWnd->RecalcLayout();

   return pOldActiveView;
}
这个单文档的具体的生成方法和多文档还是有区别的,认真看一下,   ::SetWindowLong

(pOldActiveView->m_hWnd, GWL_ID, 0); ::SetWindowLong(pNewView->m_hWnd, GWL_ID,

AFX_IDW_PANE_FIRST);这两个函数是用来操作窗体的具体的属性的。而在多文档里这个是没有的。

还有一种方法如下,就不做过多解释了
1、创建
BOOL CMultiViewApp::InitInstance()
{
 AfxEnableControlContainer();

 // Standard initialization
 // If you are not using these features and wish to reduce the size
 //  of your final executable, you should remove from the following
 //  the specific initialization routines you do not need.

#ifdef _AFXDLL
 Enable3dControls();   // Call this when using MFC in a shared DLL
#else
 Enable3dControlsStatic(); // Call this when linking to MFC statically
#endif

 // Change the registry key under which our settings are stored.
 // TODO: You should modify this string to be something appropriate
 // such as the name of your company or organization.
 SetRegistryKey(_T("Local AppWizard-Generated Applications"));

 LoadStdProfileSettings();  // Load standard INI file options (including MRU)

 // Register the application's document templates.  Document templates
 //  serve as the connection between documents, frame windows and views.

 CSingleDocTemplate* pDocTemplate;
 pDocTemplate = new CSingleDocTemplate(
  IDR_MAINFRAME,
  RUNTIME_CLASS(CMultiViewDoc),
  RUNTIME_CLASS(CMainFrame),       // main SDI frame window
  RUNTIME_CLASS(CMultiViewView));
 AddDocTemplate(pDocTemplate);

 // Parse command line for standard shell commands, DDE, file open
 CCommandLineInfo cmdInfo;
 ParseCommandLine(cmdInfo);

 // Dispatch commands specified on the command line
 if (!ProcessShellCommand(cmdInfo))
  return FALSE;

 CView* pActiveView = ((CFrameWnd*) m_pMainWnd)->GetActiveView();
 m_pFirstView = pActiveView;
 m_pOtherView = (CView*) new COtherView;

 CDocument* pDoc = ((CFrameWnd*)m_pMainWnd)->GetActiveDocument();

 CCreateContext context;
 context.m_pCurrentDoc = pDoc;

 UINT m_ID = AFX_IDW_PANE_FIRST + 1;
 CRect rect;

 m_pOtherView->Create(NULL, NULL, WS_CHILD, rect, m_pMainWnd, m_ID, &context);

 // The one and only window has been initialized, so show and update it.
 m_pMainWnd->ShowWindow(SW_SHOWMAXIMIZED);
 m_pMainWnd->UpdateWindow();

 return TRUE;
}
2、两个控制函数
void CMultiViewApp::OnViewOtherview()
{
 // TODO: Add your command handler code here
 UINT temp = ::GetWindowLong(m_pOtherView->m_hWnd, GWL_ID);
    ::SetWindowLong(m_pOtherView->m_hWnd, GWL_ID, ::GetWindowLong(m_pFirstView->m_hWnd,

GWL_ID));
    ::SetWindowLong(m_pFirstView->m_hWnd, GWL_ID, temp);

 m_pFirstView->ShowWindow(SW_HIDE);
 m_pOtherView->ShowWindow(SW_SHOW);   

 ((CFrameWnd*)m_pMainWnd)->SetActiveView(m_pOtherView); 
 ((CFrameWnd*) m_pMainWnd)->RecalcLayout();
    m_pOtherView->Invalidate();
 
}

void CMultiViewApp::OnViewFirstview()
{
  // TODO: Add your command handler code here
   
    UINT temp = ::GetWindowWord(m_pOtherView->m_hWnd, GWL_ID);
    ::SetWindowWord(m_pOtherView->m_hWnd, GWL_ID, ::GetWindowWord(m_pFirstView->m_hWnd,

GWL_ID));
    ::SetWindowWord(m_pFirstView->m_hWnd, GWL_ID, temp);
 
  m_pOtherView->ShowWindow(SW_HIDE);
  m_pFirstView->ShowWindow(SW_SHOW);   
  
  ((CFrameWnd*)m_pMainWnd)->SetActiveView(m_pFirstView); 
  ((CFrameWnd*)m_pMainWnd)->RecalcLayout();
    m_pFirstView->Invalidate();
}
二、多文档中一个文档带多视图,可以用这种方法:
1、在打开文件(任何一种方法都可以,这里只是为了方便测试)里创建交换视图的方法
void CMdiDoc::OnFileOpen()
{
 // TODO: Add your command handler code here
 CMyEditView * p = new CMyEditView();

 if (NULL != p)
 {
     CMDIFrameWnd* pMainWnd = (CMDIFrameWnd*)AfxGetMainWnd();
   // Get the active MDI child window.

   CMDIChildWnd* pChild = (CMDIChildWnd*)pMainWnd->MDIGetActive();
    CCreateContext context;
 context.m_pCurrentDoc = this;
 //下面这个PCHILD很重要,否则在下面的CRTATE中通不过断言  AFX_IDW_PANE_FIRST+1 不能加1
 p->Create(NULL, NULL,  AFX_WS_DEFAULT_VIEW,CFrameWnd::rectDefault , pChild,

AFX_IDW_PANE_FIRST , /*&context*/NULL);
 this->SwitchToView(p);
  }
}
在这里注意的是注释的地方,如果不使用子窗口的CWND*,那么在下面的步骤里,pChild-

>SetActiveView(pNewView);会报断言ASSERT(IsChild(pViewNew)) 错误,同样在CRTATE里如果不使用

AFX_WS_DEFAULT_VIEW参数,在下面的AddView(pNewView)里会报一个断言说他的DOCUMENT错误,如果

AFX_IDW_PANE_FIRST变成别的,则无法出现真正的视图,同样最后一个应该是NULL。
2、创建交换的具体执行函数
CView* CMdiDoc::SwitchToView(CView *pNewView)
{
   CMDIFrameWnd* pMainWnd = (CMDIFrameWnd*)AfxGetMainWnd();

   // Get the active MDI child window.

   CMDIChildWnd* pChild = (CMDIChildWnd*)pMainWnd->MDIGetActive();

   // Get the active view attached to the active MDI child window.

   CView* pOldActiveView = pChild->GetActiveView();

   // Set flag so that document will not be deleted when view is dettached.

   BOOL bAutoDelete = m_bAutoDelete;
   m_bAutoDelete = FALSE;

   // Dettach existing view

   RemoveView(pOldActiveView);

   // restore flag

   m_bAutoDelete = bAutoDelete;

   // Show the newly active view and hide the inactive view.

   pNewView->OnInitialUpdate();
   pNewView->ShowWindow(SW_SHOW);
   pOldActiveView->ShowWindow(SW_HIDE);
   pChild->SetActiveView(pNewView);//创建于子窗体的窗口----注意这里

   // Attach new view

   AddView(pNewView);///---注意这里

   pChild->RecalcLayout();
   pNewView->UpdateWindow();
  
   return pOldActiveView;
}

能过这两个步骤就可以动态的调换你的视图了,这个视图的动态加载与在APP里的CMdiApp::InitInstance

函数中的模板加载没有太大的关系,当然,你总得加载一个吧。
网上有很多的方法,用上下文啊之类的,都试过,不太好使,可能还是大家没有弄清楚到底这个视图是什

么原因的问题,其实都是一些小的细节的东西。

三、多文档程序通过在APP类中的CMdiApp::InitInstance()中的ProcessShellCommand()这个函数来确定

1、启动时是否分发命令行消息,其实就是下面:
 CCommandLineInfo cmdInfo;
 ParseCommandLine(cmdInfo);

 // Dispatch commands specified on the command line
 if (!ProcessShellCommand(cmdInfo))
  return FALSE;  

如果想不启动创建新文档可以用如下的方法:
直接在InitInstance()函数中用如下代码代替原来的几行即可:
 CCommandLineInfo cmdInfo;
 cmdInfo.m_nShellCommand = CCommandLineInfo::FileNothing;
 ParseCommandLine(cmdInfo);
    if (!ProcessShellCommand(cmdInfo)) return FALSE;

2、允许拖拉文件到窗口打开文件

 // Enable drag/drop open
 m_pMainWnd->DragAcceptFiles();

 // Enable DDE Execute open
 EnableShellOpen();
 RegisterShellFileTypes(TRUE);

具体的说明侯先生的书上说得很清楚,不赘述。

四、如果用CMDITabs 控件的话,就简单了,只要直接在其基础上创建后,直接调用这个类的相应函数即可.

可笑的是一个错误,担误了好长时间,在找这个类的变量时,竟然莫名其妙的搜索CTabCtrl去了,结果想当然

了.对选择动作后直接把选中的参数变成HWND一头雾水,明明是不对的啊,直到看了文档,还傻乎乎的去找

CMDITabs ,认为原来一直也在找他呢,呵呵.
这个控件的更新主要是靠Update()函数,在这个函数里,会动态的遍历当前的视图,并加载到TAB中。
在CMainFrame::OnUpdateFrameTitle会调用m_wndMDITabs.Update()方法.而每次新建文档都会调用

CMainFrame::OnUpdateFrameTitle,达到了更新视图的目的.

达到目的的方法还知道几个,但不能无限制的总结下去对吧,先一点点来。

  评论这张
 
阅读(1221)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017