QQ的上下拉的抽屉式控件估计已经深入民心了。课程设计作业需要,花了半天时间写了一个类似的控件,可以实现对每个抽屉按钮设置不同的视图控件,不过没有美化,只是有骨没有肉的控件。
//QQGroupCtrl.h文件
//QQGroupCtrl.cpp文件
if (groupinfo->Button)
{
delete groupinfo->Button;
}
if (groupinfo->m_pWnd)
{
delete groupinfo->m_pWnd;
}
Iter++ ;
}
}
BEGIN_MESSAGE_MAP(QQGroupCtrl, CWnd)
END_MESSAGE_MAP()
BOOL QQGroupCtrl::Create(LPCTSTR lpszWindowName, DWORD dwStyle, const RECT &rect,
CWnd *pParentWnd, UINT uID)
{
CWnd* pWnd = this;
return pWnd->Create(NULL, lpszWindowName, dwStyle, rect, pParentWnd, uID);
}
bool QQGroupCtrl::AddOneGroup(TCHAR* szName, CWnd *pWnd)
{
TGroupInfo* ginfo=new TGroupInfo;
ginfo->m_szName=CString(szName);
ginfo->m_pWnd=pWnd;
QQGroupButton* b=new QQGroupButton;
CRect rect(0,0,0,0);
b->Create(ginfo->m_szName,WS_CHILD|WS_VISIBLE,rect,this,m_initBUttonID);
ginfo->Button=b;
m_vecGroups.push_back(ginfo);
//每加进一个组,重新计算面板的大小
CRect groupClient;
GetClientRect(&groupClient);
int index=0;
int count=m_vecGroups.size();//总数
vector <TGroupInfo*>::iterator Iter;
for ( Iter = m_vecGroups.begin( ) ; Iter != m_vecGroups.end( ) ; Iter++ )
{
TGroupInfo* groupinfo=*Iter;
//计算按钮的坐标
if (index==0)
{
CPoint leftPoint(0,0);
CSize bsize(groupClient.Width(),GROUPCTRL_HIGHT);
CRect rect(leftPoint,bsize);
groupinfo->Button->MoveWindow(rect);
}
else
{
//从下往上数的高度是bottom-(count-index)*buttonHight
CSize bsize(groupClient.Width(),GROUPCTRL_HIGHT);
CPoint leftPoint(0,groupClient.bottom-(count-index)*GROUPCTRL_HIGHT);
CRect rect(leftPoint,bsize);
groupinfo->Button->MoveWindow(rect);
}
//计算按钮的所对应窗口的坐标,即传来的pwnd
if (groupinfo->m_pWnd)//移动到按钮的下面
{
CPoint leftPoint(0,index*GROUPCTRL_HIGHT+GROUPCTRL_HIGHT);
CSize bsize(groupClient.Width(),groupClient.Height()-count*GROUPCTRL_HIGHT);
CRect rect(leftPoint,bsize);
groupinfo->m_pWnd->MoveWindow(rect);
if (index==0)
{
groupinfo->m_pWnd->ShowWindow(SW_SHOW);
}
else
{
groupinfo->m_pWnd->ShowWindow(SW_HIDE);
}
}
index++;
m_initBUttonID++;
}
GetClientRect(&m_rtClient);
return true;
}
void QQGroupCtrl::ChangeView(QQGroupButton* selectButton)
{
vector <TGroupInfo*>::iterator Iter;
int selectIndex=0;
BOOL bPtIn=FALSE;//鼠标是否点中按钮
int count=m_vecGroups.size();
//得到上一次按钮,隐藏上次的pwnd
TGroupInfo* &lastinfo=m_vecGroups.at(m_iDown);
if (lastinfo->m_pWnd)
{
lastinfo->m_pWnd->ShowWindow(SW_HIDE);
}
//得到选择索引
for ( Iter = m_vecGroups.begin( ) ; Iter != m_vecGroups.end( ) ; Iter++ )
{
TGroupInfo* groupinfo=*Iter;
if (selectButton==groupinfo->Button)
{
bPtIn=TRUE;
break;
}
selectIndex++;
}
if (!bPtIn)//没有点中
{
return ;
}
int i=0;
for ( Iter = m_vecGroups.begin( ) ; Iter != m_vecGroups.end( ) ; Iter++ )
{
TGroupInfo* groupinfo=*Iter;
//所选择的分组以及其以上的所有分组,均上移
if (i<=selectIndex)
{
groupinfo->Button->MoveWindow(0,i*GROUPCTRL_HIGHT,m_rtClient.Width(),GROUPCTRL_HIGHT,TRUE);
}
//所选择的分组以下的分组下移,不包括自己
else
{
if (selectIndex+1<count)
groupinfo->Button->MoveWindow(0,m_rtClient.bottom-(count-i)*GROUPCTRL_HIGHT,m_rtClient.Width(),GROUPCTRL_HIGHT,TRUE);
}
i++;//索引值
}
//显示所选择的分组窗口
TGroupInfo* ¤tInfo=m_vecGroups.at(selectIndex);
if (currentInfo->m_pWnd)
{
currentInfo->m_pWnd->ShowWindow(SW_SHOW);//显示本次的pwnd
}
//保存选中的按钮索引
m_iDown=selectIndex;
//UpdateWindow和Invalidate都不行,只能这样刷新了
ShowWindow(SW_HIDE);
ShowWindow(SW_SHOW);
}
原理不太难,在AddOneGroup传来的视图控件位置,是根据按钮的多少事先来调整的。而你每次按分组控件时候,所按分组以及以上的分组全部上移,所按分组的下移部分全部下移。同时,先保存一个上次按钮的索引,来隐藏上次的视图,再显示新的所选索引的视图即可。
使用代码:
QQGroupCtrl* gCtrl=new QQGroupCtrl;
gCtrl->Create(L"group",WS_VISIBLE | WS_CHILD, rect, this, 10000);
gCtrl->AddOneGroup(L"我的好友",NULL);
gCtrl->AddOneGroup(L"我的群组",NULL);
gCtrl->AddOneGroup(L"最近联系人",NULL);
gCtrl->AddOneGroup(L"自定义",NULL);