花了一个礼拜时间,总算把这个代码啃完了,用的虚函数还是不太了解
使用方法:
void CQQList::SetImageLists(CImageList *pImagelist) 设置关联的图像列表控件
void CQQList::AddButton(LPCSTR BtnTitle, UINT8 uID) 添加一个分类按钮,参数 分类名称,ID
void CQQList::AddButtonItems(UINT uID, CString &name, int nImageIndex) 为分类按钮uID添加一个项目,指定名称和图标
CQQList::m_pItemDlbFun 设置回调函数,响应项目双击事件
ListButton.h QQList的分类按钮,内含一些具体项目
class CListButton : public CButton { public: CListButton(void); ~CListButton(void); public: UINT m_Index; //分类按钮的ID BOOL m_Toped; //分类按钮的位置 CStringList m_Entities; //具体项目的名称 CStringList m_Image; //具体项目的图标 private: const UINT GetHeight()const; const UINT GetWidth()const; public: virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); };
ListButton.cpp
#include "ListButton.h" CListButton::CListButton(void) : m_Index(0) , m_Toped(FALSE) { } CListButton::~CListButton(void) { } const UINT CListButton::GetHeight()const { CRect rect; GetClientRect(rect); return rect.Height(); } const UINT CListButton::GetWidth()const { CRect rect; GetClientRect(rect); return rect.Width(); } void CListButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) { CRect rect; GetClientRect(rect); CDC dc; dc.Attach(lpDrawItemStruct->hDC); dc.SetBkMode(TRANSPARENT); CBrush m_Brush(RGB(100,140,200)); dc.SelectObject(&m_Brush); dc.DrawEdge(rect,BDR_RAISEDINNER|BDR_RAISEDOUTER ,BF_BOTTOMLEFT|BF_TOPRIGHT); dc.Draw3dRect(rect,RGB(51,51,51),RGB(0,0,0)); CRect rc(rect); rc.DeflateRect(2,2,2,2); dc.FillRect(rc,&m_Brush); CString str; GetWindowText(str); dc.SetTextColor(RGB(255,255,255)); dc.DrawText(str,CRect(0,0,rect.right,rect.bottom), DT_CENTER|DT_VCENTER|DT_SINGLELINE); }
QQList.h
typedef void(ItemDlbFun)(const CListCtrl *pListCtrl,int nItemIndex); class CQQList : public CListCtrl { public: CQQList(void); ~CQQList(void); public: void SetImageLists(CImageList *pImageList); //设置项目关联的ImageList void AddButton(LPCSTR Btext, UINT8 nID); //向List增加一个分类按钮 void AddButtonItems(UINT nIndex,CString &strItem,int mImageIdex); //向分类按钮增加一个项目 ItemDlbFun *m_pItemDlbFun; //外部的回调函数 public: virtual void PreSubclassWindow(void); BOOL PreTranslateMessage(MSG * pMsg); //截获双击事件,调用回调函数 virtual BOOL OnCmdMsg(UINT nID, int nCode, void * pExtra, AFX_CMDHANDLERINFO * pHandlerInfo); private: CListCtrl m_ClientList; CPtrArray m_pButton; UINT m_ButtonHeight; UINT m_LeftMargin; private: UINT GetTopBtnsHeightSum(void); UINT GetBtmBtnsHeightSum(void); UINT GetFirstBtmIndex(void); CRect GetNewButtonsRect(void); CRect GetListClientRect(); void MoveDown(UINT bIndex); void MoveUp(UINT bIndex); UINT CommandToIndex(UINT nID); void ShowButtonItems(UINT nIndex); void OnButtonDown(UINT bIndex, UINT nID); };
QQList.cpp
#include "QQList.h" #include "ListButton.h" CQQList::CQQList(void) : m_ButtonHeight(25) , m_LeftMargin(0) , m_pItemDlbFun(NULL) { } CQQList::~CQQList(void) { int m = m_pButton.GetSize(); for( int i=0;i<m_pButton.GetSize();i++ ) { ((CListButton *)m_pButton[i])->DestroyWindow(); delete((CListButton *)m_pButton[i]); } } /************************************************************ 虚函数 ************************************************************/ void CQQList::PreSubclassWindow(void) { m_ClientList.Create(LVS_ICON,CRect(0,0,0,0),this,101); m_ClientList.ShowWindow(SW_SHOW); m_ClientList.SetExtendedStyle(LVS_EX_FLATSB); m_ClientList.SetBkColor(RGB(255,255,255)); m_ClientList.SetTextBkColor(RGB(255,255,255)); m_ClientList.SetTextColor(RGB(0,0,255)); m_ClientList.Arrange(LVA_ALIGNLEFT); CListCtrl::PreSubclassWindow(); } BOOL CQQList::PreTranslateMessage(MSG * pMsg) { if((pMsg->hwnd==m_ClientList.m_hWnd)&&(pMsg->message==WM_LBUTTONDBLCLK)) { int index; index = m_ClientList.GetSelectionMark(); if (m_pItemDlbFun != NULL) m_pItemDlbFun(&m_ClientList,index); } return CListCtrl::PreTranslateMessage(pMsg); } UINT CQQList::CommandToIndex(UINT nID) { for(int i = 0;i< m_pButton.GetSize();i++) { if(((CListButton*)m_pButton[i])->GetDlgCtrlID()==nID) { return ((CListButton*)m_pButton[i])->m_Index; } } return -1; } BOOL CQQList::OnCmdMsg(UINT nID, int nCode, void * pExtra, AFX_CMDHANDLERINFO * pHandlerInfo) { int index = CommandToIndex(nID); if(index != -1) { OnButtonDown(index,nID); } m_ClientList.OnCmdMsg(nID,nCode,pExtra,pHandlerInfo); return CListCtrl::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo); } /************************************************************ 区域计算 ************************************************************/ CRect CQQList::GetNewButtonsRect(void) { const int EXIST_BTN_NUM = m_pButton.GetSize(); int sumheight = 0; int i = 0; while( i<EXIST_BTN_NUM ) { sumheight += ((CListButton*)m_pButton[i])->GetHeight(); i++; } CRect TotalRect; GetClientRect(TotalRect); return CRect(0,sumheight,TotalRect.Width(),sumheight+m_ButtonHeight); } UINT CQQList::GetTopBtnsHeightSum(void) { UINT result = 0; for(int i = 0; i< m_pButton.GetSize();i++) { CListButton* aBtn = (CListButton*)m_pButton[i]; if(aBtn->m_Toped) { result += aBtn->GetHeight(); } } return result; } UINT CQQList::GetBtmBtnsHeightSum(void) { UINT result = 0; for(int i = 0; i< m_pButton.GetSize();i++) { CListButton* aBtn = (CListButton*)m_pButton[i]; if (aBtn->m_Toped==FALSE) { result += aBtn->GetHeight(); } } return result; } CRect CQQList::GetListClientRect() { CRect TotalRect; GetClientRect(TotalRect); int TopHeight = GetTopBtnsHeightSum(); int BtmHeight = GetBtmBtnsHeightSum(); CRect ClientRect(0,TopHeight,TotalRect.Width(),TotalRect.Height()-BtmHeight); return ClientRect; } /************************************************************ ************************************************************/ UINT CQQList::GetFirstBtmIndex(void) { for(int i = 0; i<m_pButton.GetSize();i++) { if (((CListButton*)m_pButton[i])->m_Toped==FALSE) return i; } return -1; } void CQQList::MoveDown(UINT bIndex) { UINT BtmOffset = m_pButton.GetSize()-1-bIndex; CListButton* target = (CListButton*)m_pButton[bIndex]; CRect wholeRect; GetClientRect(wholeRect); CRect rect( 0, wholeRect.bottom - (target->GetHeight())*(BtmOffset+1), target->GetWidth(), wholeRect.bottom - (target->GetHeight())*(BtmOffset) ); target->MoveWindow(rect); target->m_Toped = FALSE; } void CQQList::MoveUp(UINT bIndex) { CListButton* target = (CListButton*)m_pButton[bIndex]; CRect wholeRect; GetClientRect(wholeRect); CRect rect( 0, wholeRect.top + (target->GetHeight())*(bIndex), target->GetWidth(), wholeRect.top + (target->GetHeight())*(bIndex+1) ); target->MoveWindow(rect); target->m_Toped = TRUE; } //显示第nIndex个按钮内的内容 void CQQList::ShowButtonItems(UINT nIndex) { m_ClientList.DeleteAllItems(); CRect showrect = GetListClientRect(); const UINT LEFT_MARGIN = showrect.Width()/2-20; CListButton* temp = (CListButton*)m_pButton[nIndex]; if(temp->m_Entities.GetCount()>0) { int m = 0; POSITION pos = temp->m_Entities.GetHeadPosition(); POSITION index = temp->m_Image.GetHeadPosition(); while( pos != NULL && index != NULL ) { CString itemName = temp->m_Entities.GetNext(pos); int itemId = atoi(temp->m_Image.GetNext(index)); m_ClientList.InsertItem(m,itemName,itemId); m_ClientList.SetItemPosition(m,CPoint(LEFT_MARGIN,m*(48+5))); m++; }; } } void CQQList::OnButtonDown(UINT btnIdx, UINT nID) { if(m_pButton.GetSize()<2) { return; } CListButton* aBtn = (CListButton*)m_pButton[btnIdx]; if(aBtn->m_Toped) { int targetBtnIdx = m_pButton.GetSize()-1; while( targetBtnIdx>btnIdx ) { MoveDown(targetBtnIdx--); } } else { int targetBtnIdx = GetFirstBtmIndex(); while( targetBtnIdx<=btnIdx ) { MoveUp(targetBtnIdx++); } } CRect rectclt = GetListClientRect(); m_ClientList.MoveWindow(rectclt); ShowButtonItems(btnIdx); } /************************************************** 用户接口 **************************************************/ void CQQList::SetImageLists(CImageList *pImagelist) { if(pImagelist) m_ClientList.SetImageList(pImagelist,LVSIL_NORMAL); } void CQQList::AddButton(LPCSTR BtnTitle, UINT8 uID) { CListButton *pBtn = new CListButton; pBtn->Create(BtnTitle,WS_CHILD|BS_OWNERDRAW,GetNewButtonsRect(),this,uID); pBtn->m_Index = m_pButton.GetSize(); pBtn->ShowWindow(SW_SHOW); m_pButton.Add(pBtn); } void CQQList::AddButtonItems(UINT nIndex, CString &name, int nImageIdex) { CListButton* temp = (CListButton*)m_pButton[nIndex]; temp->m_Entities.AddTail(name); CString strIndex; strIndex.Format("%d",nImageIdex); temp->m_Image.AddTail(strIndex); }