百叶窗式面板组

利用百叶窗式面板组可增大窗口的可利用面积,而且把常用工具放在窗口中比放在菜单中使用更方便,现在一些大型软件如Photoshop、Dreamweaver等都采用了这种方式。在这些软件中,百叶窗式面板组都做成了可停靠的窗口,我没有这种能力,只能做成固定位置的控件组,使用时只能用在对话框或具有CFormView的视图中,整个制作很粗糙,希望高手能加以改造。


示例程序运行图

本程序的核心思路是调整控件的位置和显示/隐藏控件,当一个面板被收起或展开时,只要把它下面的控件都隐藏或显示出来,再调整各面板控件位置,这样整个面板组就像百叶窗一样可以收放自如了。

显示/隐藏控件:

CWnd*pWnd;
pWnd=GetDlgItem(控件ID号);
pWnd->ShowWindow(nShow);

GetDlgItem()函数用于获取控件的指针;

ShowWindow()函数用于显示/隐藏控件,当nShow为SW_SHOW时,显示控件,为SW_HIDE时隐藏控件。

修改控件位置:

CWnd*pWnd;
pWnd=GetDlgItem(控件ID号);
pWnd->SetWindowPos(NULL,x,y,0,0,SWP_NOZORDER|SWP_NOSIZE);

SetWindowPos()函数把控件移到窗口的(x,y)处,大小不变

这个程序的设计难点在控制控件的位置上,应该尽量采用相对位置。在这里只要抓住在各种情况下标题条的位置就可以了,标题条下的各控件位置都是相对于标题条的,当标题条位置改变时,重新计算一下控件位置就可以了。

我定义了一个数组变量CPoint m_TitlePt[3]存放三个标题条的位置,其值在收放面板时进行设定。

面板1的标题条是固定的,只要设置好初值就行了;

面板2的标题条是相对于面板1的标题条的,有两种可能(如图):

当面版1展开时,其y坐标=标题条1.y+面板1高度,即:m_TitlePt[1].y = m_TitlePt[0].y+m_BoxHeight[0];

当面版1收起时,其y坐标=标题条1.y+标题条1高度,即:m_TitlePt[1].y = m_TitlePt[0].y+m_TitleHeight;

面板1是展开的
面板1是收起的

面板3的标题条是相对于面板2的标题条的,也有两种可能(如图):

当面版2展开时,其y坐标=标题条2.y+面板2高度,即:m_TitlePt[2].y = m_TitlePt[1].y+m_BoxHeight[1];

当面版2收起时,其y坐标=标题条2.y+标题条2高度,即:m_TitlePt[2].y = m_TitlePt[1].y+m_TitleHeight;

面板2是展开的
面板2是收起的

示例中的三个面板控制方法是一样的,当单击一个面板的标题条时,除了展开或收起本标题条外,其它两个面板也需要调节,以下只就面板3为例,说明一下它们的联动方法,其它两个面板的控制与此完全类似。

先看是计算面板3各部分位置的函数:

voidCCurtainBoxDlg::CalculateControlPos3()
{
m_TitlePt[2].x=m_BoxRext.left;//标题条位置(左上角坐标)
if(b_Mark2)//面板2是展开的
m_TitlePt[2].y=m_TitlePt[1].y+m_BoxHeight[1];
else//面板2是收起的
m_TitlePt[2].y=m_TitlePt[1].y+m_TitleHeight;
m_ControlPt3[0]=CPoint(m_TitlePt[2].x+5,m_TitlePt[2].y+m_TitleHeight+7);//控件位置
m_ControlPt3[1]=CPoint(m_TitlePt[2].x+85,m_TitlePt[2].y+m_TitleHeight+7);
m_ControlPt3[2]=CPoint(m_TitlePt[2].x+5,m_TitlePt[2].y+m_TitleHeight+35);
}

这里主要是先确定标题条位置,面板下各控件位置都是相对于标题条的。

计算好位置后,就可以重新定位位置了,以下为设置面板3各部分位置的函数:

voidCCurtainBoxDlg::SetBox3Pos()
{
CWnd*pWnd=GetDlgItem(IDC_TITLE3);
pWnd->SetWindowPos(NULL,m_TitlePt[2].x,m_TitlePt[2].y,
0,0,SWP_NOSIZE|SWP_NOZORDER);//调整标题栏位置
inti;
for(i=0;i<BOX3_NUMBER;i++)
{
pWnd=GetDlgItem(m_Box3ID[i]);
pWnd->SetWindowPos(NULL,m_ControlPt3[i].x,m_ControlPt3[i].y,
0,0,SWP_NOSIZE|SWP_NOZORDER);//调整控件位置
}
}

其中,BOX3_NUMBER为面板3中控件数,m_Box3ID[]存放控件ID号的数组,其值在初始化时已设置。

解决了控件位置后,就该考虑单击标题条后的调整问题了。

由于标题条是一种自绘的按钮,可直接用ClassWizard添加它们的响应函数,这里我用了三个BOOL变量监视标题条状态:

BOOLb_Mark1;//面板1状态:true-展开、false-收缩
BOOLb_Mark2;//面板2状态
BOOLb_Mark3;//面板3状态

当单击一个标题条时,首先修改它的状态变量,再根据新状态,计算和设置各控件位置,再重绘整个控件组就行了。还有一个问题,为了节省空间,我只允许同时展开两个面板,所以当展开一个面板时,若其它两个面板处于打开状态就应该先关闭一个。

以下为单击面板3的标题条时的响应函数:

voidCCurtainBoxDlg::OnTitle3()
{
if(m_Title3.ClickBut())
{
b_Mark3=!b_Mark3;
if(b_Mark1&&b_Mark2&&b_Mark3)
{
b_Mark1=false;
m_Title1.SetButStatus(BUT_STATUS_RIGHT);
ShowBox1(SW_HIDE);
}
if(b_Mark3)
ShowBox3(SW_SHOW);
else
ShowBox3(SW_HIDE);
InvalidateBox();//刷新面板组
}
}

m_Title3.ClickBut()是自绘的标题条按钮的成员函数,用于判定单击处是否为标题条的文字部分(参见示例中的CTitleBox类);

b_Mark3 = !b_Mark3为更改面板3的状态;

再判定若三个面板都是展开的,则关闭面板1。

ShowBox3()为显示/隐藏面板3中各控件的函数,定义为:

voidCCurtainBoxDlg::ShowBox3(intnShow)
{
CWnd*pWnd;
for(inti=0;i<BOX3_NUMBER;i++)
{
pWnd=GetDlgItem(m_Box3ID[i]);
pWnd->ShowWindow(nShow);
}
}

InvalidateBox()调用计算和设置控件位置函数刷新面板组:

voidCCurtainBoxDlg::InvalidateBox()
{
CalculateControlPos1();//计算面板1各控件位置
SetBox1Pos();//重新设置面板1各控件位置
CalculateControlPos2();//计算面板2各控件位置
SetBox2Pos();//重新设置面板2各控件位置
CalculateControlPos3();//计算面板3各控件位置
SetBox3Pos();//重新设置面板3各控件位置
InvalidateRect(&m_BoxRext);//重绘面板背景以消除残留印记
}

这个函数是实现各面板联动的关键,不论单击哪一个标题条,都要调用这个函数,它重新计算并设置各面板位置。

以上为百叶窗式面板组的设计思路,完整代码参见示例程序。

本文所用MFC函数速查:

CPoint::CPoint
CWnd::GetDlgItem
CWnd::SetWindowPos
CWnd::ShowWindow

http://221.199.150.103/jsj/Html/vc/wen/vcwen07.htm

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值