QQ分组控件的简单实现

来源:互联网 发布:布施知子是谁 编辑:程序博客网 时间:2024/04/28 02:56

原文:http://blog.csdn.net/rabbitguiming/archive/2009/05/03/4144278.aspx

 

QQ的上下拉的抽屉式控件估计已经深入民心了。课程设计作业需要,花了半天时间写了一个类似的控件,可以实现对每个抽屉按钮设置不同的视图控件,不过没有美化,只是有骨没有肉的控件。

//QQGroupCtrl.h文件

view plaincopy to clipboardprint?
#pragma once  
#include <vector>  
using namespace std;  
// QQGroupCtrl  
#define GROUPCTRL_HIGHT 22  
#define GROUPCTRL_INITBUTTONID 90000//分组按钮的id号,自增  
//QQ分组按钮  
class QQGroupButton : public CButton  
{  
    DECLARE_DYNAMIC(QQGroupButton)  
public:  
    QQGroupButton();  
    virtual ~QQGroupButton();  
protected:  
    DECLARE_MESSAGE_MAP()  
public:  
    afx_msg void OnLButtonDown(UINT nFlags, CPoint point);  
};  
//分组按钮信息,关联按钮和窗口  
class TGroupInfo  
{  
public:  
    TGroupInfo():m_szName(_T("")), m_pWnd(NULL){}  
    virtual ~TGroupInfo(){}  
public:  
    CString     m_szName;                                           // 组名称  
    CWnd        *m_pWnd;                                            // 组窗口指针  
    QQGroupButton   *Button;                                                //自己  
};  
//分组控件,包含N个分组  
class QQGroupCtrl : public CWnd  
{  
    DECLARE_DYNAMIC(QQGroupCtrl)  
public:  
    QQGroupCtrl();  
    virtual ~QQGroupCtrl();  
protected:  
    DECLARE_MESSAGE_MAP()  
public:  
    virtual BOOL Create(LPCTSTR lpszWindowName, DWORD dwStyle, const RECT &rect,  
        CWnd *pParentWnd, UINT uID);  
    bool AddOneGroup(TCHAR* szName, CWnd *pWnd = NULL);   
    void ChangeView(QQGroupButton* selectButton);  
private:  
    vector<TGroupInfo*>       m_vecGroups;// 组信息列表  
    int     m_iDown;        // 当前鼠标按下的索引  
    CRect   m_rtClient;     // 客户区大小  
    int     m_initBUttonID; //初始化按钮id  
}; 
#pragma once
#include <vector>
using namespace std;
// QQGroupCtrl
#define GROUPCTRL_HIGHT 22
#define GROUPCTRL_INITBUTTONID 90000//分组按钮的id号,自增
//QQ分组按钮
class QQGroupButton : public CButton
{
 DECLARE_DYNAMIC(QQGroupButton)
public:
 QQGroupButton();
 virtual ~QQGroupButton();
protected:
 DECLARE_MESSAGE_MAP()
public:
 afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
};
//分组按钮信息,关联按钮和窗口
class TGroupInfo
{
public:
 TGroupInfo():m_szName(_T("")), m_pWnd(NULL){}
 virtual ~TGroupInfo(){}
public:
 CString  m_szName;           // 组名称
 CWnd  *m_pWnd;           // 组窗口指针
 QQGroupButton *Button;            //自己
};
//分组控件,包含N个分组
class QQGroupCtrl : public CWnd
{
 DECLARE_DYNAMIC(QQGroupCtrl)
public:
 QQGroupCtrl();
 virtual ~QQGroupCtrl();
protected:
 DECLARE_MESSAGE_MAP()
public:
 virtual BOOL Create(LPCTSTR lpszWindowName, DWORD dwStyle, const RECT &rect,
  CWnd *pParentWnd, UINT uID);
 bool AddOneGroup(TCHAR* szName, CWnd *pWnd = NULL); 
 void ChangeView(QQGroupButton* selectButton);
private:
 vector<TGroupInfo*>  m_vecGroups;// 组信息列表
 int  m_iDown;  // 当前鼠标按下的索引
 CRect m_rtClient;  // 客户区大小
 int  m_initBUttonID; //初始化按钮id
};


 

//QQGroupCtrl.cpp文件

view plaincopy to clipboardprint?
// QQGroupCtrl.cpp : 实现文件  
//  
#include "stdafx.h"  
#include "CustomQQ.h"  
#include "QQGroupCtrl.h"  
#include "Mmsystem.h"  
// QQGroupButton  
IMPLEMENT_DYNAMIC(QQGroupButton, CButton)  
QQGroupButton::QQGroupButton()  
{  
}  
QQGroupButton::~QQGroupButton()  
{  
}  
BEGIN_MESSAGE_MAP(QQGroupButton, CButton)  
    ON_WM_LBUTTONDOWN()  
END_MESSAGE_MAP()  
void QQGroupButton::OnLButtonDown(UINT nFlags, CPoint point)  
{     
    QQGroupCtrl* parent=(QQGroupCtrl*)this->GetParent();  
    parent->ChangeView(this);//分组按钮  
    CButton::OnLButtonDown(nFlags,point);  
}  
//////////////////////////////////////////////////////////////////////////  
// QQGroupCtrl  
IMPLEMENT_DYNAMIC(QQGroupCtrl, CWnd)  
QQGroupCtrl::QQGroupCtrl()  
{  
    m_initBUttonID=GROUPCTRL_INITBUTTONID;  
    m_iDown=0;//选中的分组索引  
}  
//析构  
QQGroupCtrl::~QQGroupCtrl()  
{  
    vector <TGroupInfo*>::iterator Iter=m_vecGroups.begin( ) ;  
    while (Iter != m_vecGroups.end( ))  
    {  
        TGroupInfo* groupinfo=*Iter;  
          
        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* &currentInfo=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);  

// QQGroupCtrl.cpp : 实现文件
//
#include "stdafx.h"
#include "CustomQQ.h"
#include "QQGroupCtrl.h"
#include "Mmsystem.h"
// QQGroupButton
IMPLEMENT_DYNAMIC(QQGroupButton, CButton)
QQGroupButton::QQGroupButton()
{
}
QQGroupButton::~QQGroupButton()
{
}
BEGIN_MESSAGE_MAP(QQGroupButton, CButton)
 ON_WM_LBUTTONDOWN()
END_MESSAGE_MAP()
void QQGroupButton::OnLButtonDown(UINT nFlags, CPoint point)

 QQGroupCtrl* parent=(QQGroupCtrl*)this->GetParent();
 parent->ChangeView(this);//分组按钮
 CButton::OnLButtonDown(nFlags,point);
}
//////////////////////////////////////////////////////////////////////////
// QQGroupCtrl
IMPLEMENT_DYNAMIC(QQGroupCtrl, CWnd)
QQGroupCtrl::QQGroupCtrl()
{
 m_initBUttonID=GROUPCTRL_INITBUTTONID;
 m_iDown=0;//选中的分组索引
}
//析构
QQGroupCtrl::~QQGroupCtrl()
{
 vector <TGroupInfo*>::iterator Iter=m_vecGroups.begin( ) ;
 while (Iter != m_vecGroups.end( ))
 {
  TGroupInfo* groupinfo=*Iter;
  
  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* &currentInfo=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);

效果图

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/rabbitguiming/archive/2009/05/03/4144278.aspx

原创粉丝点击