深入浅出MFC文档/视图架构之框架(转)

来源:互联网 发布:知乎如何幼儿园合作 编辑:程序博客网 时间:2024/06/06 01:34

从前文可知,在MFC中,文档是真正的数据载体,视图是文档的显示界面,对应同一个文档,可能存在多个视图界面,我们需要另外一种东东来将这些界面管理起来,这个东东就是框架。

  MFC创造框架类的初衷在于:把界面管理工作独立出来!框架窗口为应用程序的用户界面提供结构框架,它是应用程序的主窗口,负责管理其包容的窗口。一个应用程序启动时会创建一个最顶层的框架窗口。

  MFC提供二种类型的框架窗口:单文档窗口SDI和多文档窗口MDI(你可以认为对话框是另一种框架窗口)。单文档窗口一次只能打开一个文档框架窗口,而多文档窗口应用程序中可以打开多个文档框架窗口,即子窗口(Child Window)。这些子窗口中的文档可以为同种类型,也可以为不同类型。

  在Visual C++ AppWizard的第一个对话框中,会让用户选择应用程序是基于单文档、多文档还是基于对话框的,如图5.1。


图5.1 在AppWizard中选择框架窗口


  MFC提供了三个类CFrameWnd、CMDIFrameWnd、CMDIChildWnd用于支持单文档窗口和多文档窗口,这些类的层次结构如图5.2。


图5.2 CFrameWnd、CMDIFrameWnd、CMDIChildWnd类的层次

 
  (1)CFrameWnd类用于SDI应用程序的框架窗口,SDI框架窗口既是应用程序的主框架窗口,也是当前文档对应的视图的边框;CFrameWnd类也作为CMDIFrameWnd和CMDIChildWnd类的父类,而在基于SDI的应用程序中,AppWizard会自动为我们添加一个继承自CFrameWnd类的CMainFrame类。

  CFrameWnd类中重要的函数有Create(用于创建窗口)、LoadFrame(用于从资源文件中创建窗口)、PreCreateWindow(用于注册窗口类)等。Create函数第一个参数为窗口注册类名,第二个参数为窗口标题,其余几个参数指定了窗口的风格、大小、父窗口、菜单名等,其源代码如下:
BOOL CFrameWnd::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT &rect, CWnd *pParentWnd, LPCTSTR lpszMenuName, DWORD dwExStyle, CCreateContext *pContext)
{
 HMENU hMenu = NULL;
 if (lpszMenuName != NULL)
 {
  // load in a menu that will get destroyed when window gets destroyed
  HINSTANCE hInst = AfxFindResourceHandle(lpszMenuName, RT_MENU);
  if ((hMenu = ::LoadMenu(hInst, lpszMenuName)) == NULL)
  {
   TRACE0("Warning: failed to load menu for CFrameWnd./n");
   PostNcDestroy(); // perhaps delete the C++ object
   return FALSE;
  }
 }
 m_strTitle = lpszWindowName; // save title for later

 if (!CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle, rect.left,
rect.top, rect.right - rect.left, rect.bottom - rect.top, pParentWnd
->GetSafeHwnd(), hMenu, (LPVOID)pContext))
 {
  TRACE0("Warning: failed to create CFrameWnd./n");
  if (hMenu != NULL)
   DestroyMenu(hMenu);
  return FALSE;
 }
 return TRUE;
}

 


  LoadFrame函数用于从资源文件中创建窗口,我们通常只需要给其指定一个参数,LoadFrame使用该参数从资源中获取主边框窗口的标题、图标、菜单、加速键等,其源代码为:

BOOL CFrameWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle, CWnd
*pParentWnd, CCreateContext *pContext)
{
 // only do this once
 ASSERT_VALID_IDR(nIDResource);
 ASSERT(m_nIDHelp == 0 || m_nIDHelp == nIDResource);

 m_nIDHelp = nIDResource; // ID for help context (+HID_BASE_RESOURCE)

 CString strFullString;
 if (strFullString.LoadString(nIDResource))
  AfxExtractSubString(m_strTitle, strFullString, 0);
  // first sub-string

 VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG));

 // attempt to create the window
 LPCTSTR lpszClass = GetIconWndClass(dwDefaultStyle, nIDResource);
 LPCTSTR lpszTitle = m_strTitle;
 if (!Create(lpszClass, lpszTitle, dwDefaultStyle, rectDefault, pParentWnd,
MAKEINTRESOURCE(nIDResource), 0L, pContext))
 {
  return FALSE; // will self destruct on failure normally
 }

 // save the default menu handle
 ASSERT(m_hWnd != NULL);
 m_hMenuDefault = ::GetMenu(m_hWnd);

 // load accelerator resource
 LoadAccelTable(MAKEINTRESOURCE(nIDResource));

 if (pContext == NULL)
  // send initial update
  SendMessageToDescendants(WM_INITIALUPDATE, 0, 0, TRUE, TRUE);

 return TRUE;
}


  在SDI程序中,如果需要修改窗口的默认风格,程序员需要修改CMainFrame类的PreCreateWindow函数,因为AppWizard给我们生成的CMainFrame::PreCreateWindow仅对其基类的PreCreateWindow函数进行调用,CFrameWnd::PreCreateWindow的源代码如下:

 

BOOL CFrameWnd::PreCreateWindow(CREATESTRUCT &cs)
{
 if (cs.lpszClass == NULL)
 {
  VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG));
  cs.lpszClass = _afxWndFrameOrView; // COLOR_WINDOW background
 }

 if ((cs.style &FWS_ADDTOTITLE) && afxData.bWin4)cs.style |= FWS_PREFIXTITLE;

 if (afxData.bWin4)
  cs.dwExStyle |= WS_EX_CLIENTEDGE;
 return TRUE;
}

2006-03-21 08:37作者:宋宝华出处:天极开发责任编辑:方舟

http://dev.yesky.com/301/2340801.shtml

原创粉丝点击