Posted on 2010-08-28 20:15
幻海蓝梦 阅读(1990)
评论(0) 编辑 收藏 所属分类:
C++
http://www.anqn.com/dev/vc/2009-06-15/a09111492-1.shtml
CMDIFrameWnd类用于MDI应用程序的主框架窗口,主框架窗口是所有MDI文档子窗口的容器,并与子窗口共享菜单;CMDIFrameWnd类相较CFrameWnd类增加的重要函数有:MDIActivate(激活另一个MDI子窗口)、MDIGetActive(得到目前的活动子窗口)、MDIMaximize(最大化一个子窗口)、MDINext(激活目前活动子窗口的下一子窗口并将当前活动子窗口排入所有子窗口末尾)、MDIRestore(还原MDI子窗口)、MDISetMenu(设置MDI子窗口对应的菜单)、MDITile(平铺子窗口)、MDICascade(重叠子窗口)。
Visual C++开发环境是典型的MDI程序,其执行MDI Cascade的效果如图5.3。
图5.3 MDI Cascade的效果
|
而执行MDI Tile的效果则如图5.4。
图5.4 MDI Tile的效果
|
MDISetMenu函数的重要意义体现在一个MDI程序可以为不同类型的文档(与文档模板关联)显示不同的菜单,例如下面的这个函数Load一个菜单,并将目前主窗口的菜单替换为该菜单:
void CMdiView::OnReplaceMenu()
{
// Load a new menu resource named IDR_SHORT_MENU
CMdiDoc* pdoc = GetDocument();
pdoc->m_DefaultMenu = ::LoadMenu(AfxGetResourceHandle(), MAKEINTRESOURCE(IDR_SHORT_MENU));
if (pdoc->m_DefaultMenu == NULL)
return;
// Get the parent window of this view window. The parent window is
// a CMDIChildWnd-derived class. We can then obtain the MDI parent
// frame window using the CMDIChildWnd*. Then, replace the current
// menu bar with the new loaded menu resource.
CMDIFrameWnd* frame = ((CMDIChildWnd *) GetParent())->GetMDIFrame();
frame->MDISetMenu(CMenu::FromHandle(pdoc->m_DefaultMenu), NULL);
frame->DrawMenuBar();
} |
CMDIFrameWnd类另一个不讲"不足以服众"的函数是OnCreateClient,它是子框架窗口的创造者,其实现如下:
BOOL CMDIFrameWnd::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext*)
{
CMenu* pMenu = NULL;
if (m_hMenuDefault == NULL)
{
// default implementation for MFC V1 backward compatibility
pMenu = GetMenu();
ASSERT(pMenu != NULL);
// This is attempting to guess which sub-menu is the Window menu.
// The Windows user interface guidelines say that the right-most
// menu on the menu bar should be Help and Window should be one
// to the left of that.
int iMenu = pMenu->GetMenuItemCount() - 2;
// If this assertion fails, your menu bar does not follow the guidelines
// so you will have to override this function and call CreateClient
// appropriately or use the MFC V2 MDI functionality.
ASSERT(iMenu >= 0);
pMenu = pMenu->GetSubMenu(iMenu);
ASSERT(pMenu != NULL);
}
return CreateClient(lpcs, pMenu);
} |
从CMDIFrameWnd::OnCreateClient的源代码可以看出,其中真正起核心作用的是对函数CreateClient的调用:
BOOL CMDIFrameWnd::CreateClient(LPCREATESTRUCT lpCreateStruct,
CMenu* pWindowMenu)
{
ASSERT(m_hWnd != NULL);
ASSERT(m_hWndMDIClient == NULL);
DWORD dwStyle = WS_VISIBLE | WS_CHILD | WS_BORDER | WS_CLIPCHILDREN | WS_CLIPSIBLINGS |
MDIS_ALLCHILDSTYLES; // allow children to be created invisible
DWORD dwExStyle = 0;
// will be inset by the frame
if (afxData.bWin4)
{
// special styles for 3d effect on Win4
dwStyle &= ~WS_BORDER;
dwExStyle = WS_EX_CLIENTEDGE;
}
CLIENTCREATESTRUCT ccs;
ccs.hWindowMenu = pWindowMenu->GetSafeHmenu();
// set hWindowMenu for MFC V1 backward compatibility
// for MFC V2, window menu will be set in OnMDIActivate
ccs.idFirstChild = AFX_IDM_FIRST_MDICHILD;
if (lpCreateStruct->style & (WS_HSCROLL|WS_VSCROLL))
{
// parent MDIFrame's scroll styles move to the MDICLIENT
dwStyle |= (lpCreateStruct->style & (WS_HSCROLL|WS_VSCROLL));
// fast way to turn off the scrollbar bits (without a resize)
ModifyStyle(WS_HSCROLL|WS_VSCROLL, 0, SWP_NOREDRAW|SWP_FRAMECHANGED);
}
// Create MDICLIENT control with special IDC
if ((m_hWndMDIClient = ::CreateWindowEx(dwExStyle, _T("mdiclient"), NULL,
dwStyle, 0, 0, 0, 0, m_hWnd, (HMENU)AFX_IDW_PANE_FIRST,
AfxGetInstanceHandle(), (LPVOID)&ccs)) == NULL)
{
TRACE(_T("Warning: CMDIFrameWnd::OnCreateClient: failed to create MDICLIENT.")
_T(" GetLastError returns 0x%8.8X\n"), ::GetLastError());
return FALSE;
}
// Move it to the top of z-order
::BringWindowToTop(m_hWndMDIClient);
return TRUE;
} |
(3)CMDIChildWnd类用于在MDI主框架窗口中显示打开的文档。每个视图都有一个对应的子框架窗口,子框架窗口包含在主框架窗口中,并使用主框架窗口的菜单。
CMDIChildWnd类的一个重要函数GetMDIFrame()返回目前MDI客户窗口的父窗口,其实现如下:
CMDIFrameWnd *CMDIChildWnd::GetMDIFrame()
{
HWND hWndMDIClient = ::GetParent(m_hWnd);
CMDIFrameWnd *pMDIFrame;
pMDIFrame = (CMDIFrameWnd*)CWnd::FromHandle(::GetParent(hWndMDIClient));
return pMDIFrame;
} |
利用AppWizard生成的名为"example"的MDI工程包含如图5.5所示的类。
图5.5 一个MDI工程包含的类
|
其中的CMainFrame继承自CMDIFrameWnd,CChildFrame类继承自CMDIChildWnd类,CExampleView视图类则负责在CMDIChildWnd类对应的子框架窗口中显示文档的数据。
文中只是对CMDIFrameWnd的CreateClient成员函数进行了介绍,实际上,CFrameWnd、CMDIChildWnd均包含CreateClient成员函数。我们经常通过重载CFrameWnd:: CreateClient、CMDIChildWnd:: CreateClient函数的方法来实现"窗口分割",例如:
BOOL CChildFrame::OnCreateClient(LPCREATESTRUCT lpcs,
CCreateContext *pContext)
{
…
if (!m_wndSplitter.Create(this, 2, 2, // 分割的行、列数
CSize(10, 10), // 最小化尺寸
pContext))
{
TRACE0("创建分割失败");
return FALSE;
}
…
return TRUE;
|