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里面的一些参数),但都是遇到问题后一步步改出来的,如果你有简单的方法,欢迎留言指教!

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值