MDI中重新排列view視口(子窗口)

這幾天的任務是:在一個MDI應用程序中打開多個view(子窗口),要求通過菜單實現子窗口的水平、垂直和重疊排列,在實現之前,先看一下效果圖吧。


這個功能在VC++6.0中可以通過添加菜單項後將在菜單項的ID設置爲指定ID,即可由系統自動實現這些功能,不需要添加事件處理函數(ID_WINDOW_CASCADE , ID_WINDOW_HORZ , ID_WINDOW_VERT),但是在VS2010中按照添加缺省ID的方法卻無法實現這些功能。前幾天一直在想怎麼讓系統自動實現這些功能,或者調用現成的API函數實現,但是都沒研究出想要的效果,昨天又看了一下VC++6.0的實現效果,纔想出一個簡單的實現思路,其實水平排列和垂直排列也就是在重疊排列的基礎上,重新設定一下窗口的大小和位置而已,我們可以用MoveWindow來實現這個功能,而由默認的排列方式變成重疊的排列方式,需要用到EnableMDITabbedGroups,將第一個參數設爲FALSE即可,而從重疊的排列方式轉換爲默認的排列方式時,將第一個參數設置爲TRUE就行。

另一個問題就是,在重疊的排列方式下如何遍歷所有的子窗口,逐個設置各個子窗口的位置,這裏主要用到連個函數,MDIGetactive和MDINext,獲取活動子窗口,然後依次獲取其他窗口,具體看下面的代碼吧。


void CMainFrame::OnWindowTileHorz()
{
	ArrangeChildwindow(TRUE);
}
void CMainFrame::OnWindowCascade()
{
	// TODO: Add your command handler code here
	//先將窗口轉換爲重疊排列
	CMDITabInfo  params; 
	EnableMDITabbedGroups(FALSE,params);
	//獲取已打開view窗口個數
	int count = GetOpenedViewCount();

	CRect rectClient;
	GetClientRect(&rectClient);

	if (count)
	{
		int temp = 0;
		CMDIFrameWnd* pFrame = (CMDIFrameWnd*)AfxGetMainWnd();
		if(pFrame)
		{
			CMDIChildWnd* pOldChildFrame = pFrame->MDIGetActive();
			CMDIChildWnd* pChildFrame = pOldChildFrame;
			if(pChildFrame)
			{
				do 
				{
					MDIActivate(pChildFrame);
					::MoveWindow(pChildFrame->GetSafeHwnd(),rectClient.left +(count -temp-1)*rectClient.Width()*0.05,rectClient.top+(count -temp-1)*rectClient.Height()*0.05,rectClient.Width()*0.7,rectClient.Height()*0.7,TRUE);
					
					pFrame->MDINext();
					pChildFrame = pFrame->MDIGetActive();
					temp++;
				}
				while (pChildFrame != pOldChildFrame);
			}
		}
	}

}


void CMainFrame::OnWindowTileVer()
{
	// TODO: Add your command handler code here
	ArrangeChildwindow(FALSE);
}

//“默認排列”菜單項的響應函數
void CMainFrame::OnWindowRecoverry()
{
	// TODO: Add your command handler code here
	CMDITabInfo mdiTabParams;
	mdiTabParams.m_style = CMFCTabCtrl::STYLE_3D_ONENOTE; 
	// set to FALSE to place close button at right of tab area

	mdiTabParams.m_bActiveTabCloseButton = /*FALSE*/TRUE;
	// set to TRUE to enable document icons on MDI taba

	mdiTabParams.m_bTabIcons = /*TRUE*/FALSE;    
	// set to FALSE to disable auto-coloring of MDI tabs

	mdiTabParams.m_bAutoColor = TRUE; 
	// set to TRUE to enable the document menu at the right edge of the tab area

	mdiTabParams.m_bDocumentMenu = TRUE; 
	//set to TRUE to enable the user to change the tabs positions by dragging the tabs

	mdiTabParams.m_bEnableTabSwap = TRUE;
	// set to TRUE to give each tab window has a flat frame

	mdiTabParams.m_bFlatFrame = TRUE;
	// set to TRUE to enable each tab window to display the Close button on the right edge of the tab. 

	mdiTabParams.m_bTabCloseButton = FALSE;
	// set to TRUE to enable the tabs to display tooltips.

	mdiTabParams.m_bTabCustomTooltips = TRUE;
	// Specifies that the tabs labels are located at the top of the page

	mdiTabParams.m_tabLocation = CMFCTabCtrl::LOCATION_TOP;
	EnableMDITabbedGroups(TRUE, mdiTabParams);
}

void CMainFrame::ArrangeChildwindow(BOOL IsHoriz)
{
	//先將窗口轉換爲重疊排列
	CMDITabInfo  params; 
	EnableMDITabbedGroups(FALSE,params);
	//獲取已打開view窗口個數
	int count = GetOpenedViewCount();

	CRect rectClient;
	GetClientRect(&rectClient);

	if (count)
	{
		int temp = 0;
		CMDIFrameWnd* pFrame = (CMDIFrameWnd*)AfxGetMainWnd();
		if(pFrame)
		{
			CMDIChildWnd* pOldChildFrame = pFrame->MDIGetActive();
			CMDIChildWnd* pChildFrame = pOldChildFrame;
			if(pChildFrame)
			{
				do 
				{
					if (!IsHoriz)//窗口垂直排列
					{
						::MoveWindow(pChildFrame->GetSafeHwnd(),rectClient.left + temp * rectClient.Width()/count,rectClient.top,rectClient.Width()/count,rectClient.Height(),TRUE);
					}
					else//窗口水平排列
					{
						::MoveWindow(pChildFrame->GetSafeHwnd(),rectClient.left,rectClient.top + temp * rectClient.Height()/count,rectClient.Width(),rectClient.Height()/count,TRUE);
					}


					pFrame->MDINext();
					pChildFrame = pFrame->MDIGetActive();
					temp++;
				}
				while (pChildFrame != pOldChildFrame);
			}
		}
	}
}


int CMainFrame::GetOpenedViewCount(void)
{
	//計算子窗口個數
	int count = 0;
	CMDIFrameWnd* pFrame = (CMDIFrameWnd*)AfxGetMainWnd();
	if(pFrame)
	{
		CMDIChildWnd* pOldChildFrame = pFrame->MDIGetActive();
		CMDIChildWnd* pChildFrame = pOldChildFrame;
		if(pChildFrame)
		{
			do 
			{
				pFrame->MDINext();
				pChildFrame = pFrame->MDIGetActive();
				count++;
			}
			while (pChildFrame != pOldChildFrame);
		}
	}
	return count;
}
到這裏,已經可以實現上面的功能了。

另外,在我們項目中,主框架客戶區左右兩邊各有一個面板,是的我用上面的方法獲取的rect總是不對,後來這麼改了下就行了:

CMDIChildWnd *pWndChild = ((CMainFrame*)AfxGetMainWnd())->MDIGetActive();
		MDIMaximize(pWndChild);
		pWndChild->GetClientRect(&m_rectClient);
		MDIRestore(pWndChild);
(先將子窗口最大化,獲取rect之後再還原回來)
代碼裏面可能有的地方寫得有些古怪(比如MoveWindow裏面的一些參數),但都是遇到問題後一步步改出來的,如果你有簡單的方法,歡迎留言指教!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章