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。
而執行MDI Tile的效果則如圖5.4。
MDISetMenu函數的重要意義體現在一個MDI程序可以為不同類型的文檔(與文檔模板關聯)顯示不同的菜單,例如下面的這個函數Load一個菜單,并將目前主窗口的菜單替換為該菜單:
CMDIFrameWnd類另一個不講"不足以服眾"的函數是OnCreateClient,它是子框架窗口的創造者,其實現如下:
從CMDIFrameWnd::OnCreateClient的源代碼可以看出,其中真正起核心作用的是對函數CreateClient的調用:
(3)CMDIChildWnd類用于在MDI主框架窗口中顯示打開的文檔。每個視圖都有一個對應的子框架窗口,子框架窗口包含在主框架窗口中,并使用主框架窗口的菜單。
CMDIChildWnd類的一個重要函數GetMDIFrame()返回目前MDI客戶窗口的父窗口,其實現如下:
利用AppWizard生成的名為"example"的MDI工程包含如圖5.5所示的類。
其中的CMainFrame繼承自CMDIFrameWnd,CChildFrame類繼承自CMDIChildWnd類,CExampleView視圖類則負責在CMDIChildWnd類對應的子框架窗口中顯示文檔的數據。
文中只是對CMDIFrameWnd的CreateClient成員函數進行了介紹,實際上,CFrameWnd、CMDIChildWnd均包含CreateClient成員函數。我們經常通過重載CFrameWnd:: CreateClient、CMDIChildWnd:: CreateClient函數的方法來實現"窗口分割",例如:
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; |