返回> 网站首页 

简单的自绘CListBox(三)(类似CTreeCtrl Expand效果)

yoours2011-03-23 13:43:28 阅读 1194

简介一边听听音乐,一边写写文章。

一个简单的扩展的CListBox类,点击某一个item的时候,自动展开该项来显示更多信息,类似CTreeCtrl控件的Expand样式风格。

  1. // H 文件  
  2.   
  3. #pragma once  
  4.   
  5. #include <vector>  
  6. using namespace std;  
  7. // CMultiLineListBox  
  8.   
  9. #define RGB_FOREGROUND RGB(0, 0, 0)  
  10. #define RGB_BACKGROUND RGB(255, 255, 255)  
  11. #define LISTBOX_BACKGROUND RGB(236, 255, 236)  
  12.   
  13. class CMultiLineListBox : public CListBox  
  14. {  
  15.     DECLARE_DYNAMIC(CMultiLineListBox)  
  16.   
  17. public:  
  18.     CMultiLineListBox();  
  19.     virtual ~CMultiLineListBox();  
  20.   
  21. typedef struct _LISTBOX_INFO_  
  22. {  
  23. public:  
  24.     typedef struct _SUBNODE_INFO_  
  25.     {  
  26.     public:  
  27.         CString strText;  
  28.         COLORREF fgColor;  
  29.         COLORREF bgColor;  
  30.   
  31.         _SUBNODE_INFO_()  
  32.         {  
  33.             clean();  
  34.         }  
  35.         ~_SUBNODE_INFO_()  
  36.         {  
  37.             clean();  
  38.         }  
  39.     protected:  
  40.         inline void clean(void)  
  41.         {  
  42.             strText.Empty();  
  43.             fgColor = RGB_FOREGROUND;  
  44.             bgColor = RGB_BACKGROUND;  
  45.         }  
  46.     }SUBNODEINFO, *PSUBNODEINFO;  
  47.   
  48. public:  
  49.     vector<SUBNODEINFO*> subArray;  
  50.     CString strText;  
  51.     COLORREF fgColor;  
  52.     COLORREF bgColor;  
  53.   
  54.     _LISTBOX_INFO_()  
  55.     {  
  56.         clean();  
  57.     }  
  58.     ~_LISTBOX_INFO_()  
  59.     {  
  60.         clean();  
  61.     }  
  62.   
  63. protected:  
  64.     inline void clean(void)  
  65.     {  
  66.         subArray.clear();  
  67.         strText.Empty();  
  68.         fgColor = RGB_FOREGROUND;  
  69.         bgColor = RGB_BACKGROUND;  
  70.     }  
  71. }LISTBOXINFO, * PLISTBOXINFO;  
  72.   
  73. protected:  
  74.     static int m_nFocusIndex;  
  75.     vector<LISTBOXINFO*> m_sArray;  
  76.   
  77. public:  
  78.     int InsertString(int nIndex, LPCTSTR pszText, COLORREF fgColor = RGB_FOREGROUND, COLORREF bgColor = RGB_BACKGROUND);  
  79.     int AddString(LPCTSTR pszText, COLORREF fgColor = RGB_FOREGROUND, COLORREF bgColor = RGB_BACKGROUND);  
  80.     void AddSubString(int nIndex, LPCTSTR pszText, COLORREF fgColor = RGB_FOREGROUND, COLORREF bgColor = RGB_BACKGROUND);  
  81.       
  82. protected:  
  83.     virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);  
  84.     virtual void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct);  
  85.     void UpdateItem(void);  
  86.     void GetItemHeight(int nIndex);  
  87.   
  88. protected:  
  89.     afx_msg BOOL OnEraseBkgnd(CDC* pDC);  
  90.     afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);  
  91.     afx_msg void OnLButtonDown(UINT nFlags, CPoint point);  
  92.     afx_msg void OnMouseMove(UINT nFlags, CPoint point);  
  93.     afx_msg LRESULT OnUpdateItem(WPARAM wParam, LPARAM lParam);  
  94.   
  95.     DECLARE_MESSAGE_MAP()  
  96. };  

  1. // CPP 文件  
  2.   
  3. // MultiLineListBox.cpp : implementation file  
  4. //  
  5.   
  6. #include "stdafx.h"  
  7. #include "MultiLineListBox.h"  
  8.   
  9. // CMultiLineListBox  
  10. #define MSG_UPDATEITEM WM_USER + 0x1001  
  11. #define ITEM_HEIGHT 20  
  12.   
  13. int CMultiLineListBox::m_nFocusIndex = -1;  
  14.   
  15. IMPLEMENT_DYNAMIC(CMultiLineListBox, CListBox)  
  16.   
  17. CMultiLineListBox::CMultiLineListBox()  
  18. {  
  19.     m_sArray.clear();  
  20. }  
  21.   
  22. CMultiLineListBox::~CMultiLineListBox()  
  23. {  
  24.     vector<LISTBOXINFO*>::const_iterator iter1 = m_sArray.begin();  
  25.     for(; iter1 != m_sArray.end(); ++iter1)  
  26.     {  
  27.         LISTBOXINFO* pNode = *iter1;  
  28.         vector<LISTBOXINFO::SUBNODEINFO*>::const_iterator iter2 = pNode->subArray.begin();  
  29.         for(; iter2 != pNode->subArray.end(); ++iter2)  
  30.         {  
  31.             LISTBOXINFO::SUBNODEINFO* pSubNode = *iter2;  
  32.             delete pSubNode;  
  33.             pSubNode = NULL;  
  34.         }  
  35.         delete pNode;  
  36.         pNode = NULL;  
  37.     }  
  38.     m_sArray.clear();  
  39. }  
  40.   
  41. BEGIN_MESSAGE_MAP(CMultiLineListBox, CListBox)  
  42.     ON_WM_ERASEBKGND()  
  43.     ON_WM_KEYDOWN()  
  44.     ON_WM_LBUTTONDOWN()  
  45.     ON_WM_MOUSEMOVE()  
  46.     ON_MESSAGE(MSG_UPDATEITEM, &CMultiLineListBox::OnUpdateItem)  
  47. END_MESSAGE_MAP()  
  48.   
  49. int CMultiLineListBox::InsertString(int nIndex, LPCTSTR pszText, COLORREF fgColor, COLORREF bgColor)  
  50. {  
  51.     LISTBOXINFO* pListBox = new LISTBOXINFO;  
  52.     ASSERT(pListBox);  
  53.   
  54.     ASSERT((nIndex >= 0) && (nIndex <= GetCount()));  
  55.   
  56.     pListBox->strText = pszText;  
  57.     pListBox->fgColor = fgColor;  
  58.     pListBox->bgColor = bgColor;  
  59.   
  60.     m_sArray.insert(m_sArray.begin() + nIndex, pListBox);  
  61.   
  62.     return CListBox::InsertString(nIndex, pszText);  
  63. }  
  64.   
  65. int CMultiLineListBox::AddString(LPCTSTR pszText, COLORREF fgColor, COLORREF bgColor)  
  66. {  
  67.     LISTBOXINFO* pListBox = new LISTBOXINFO;  
  68.     ASSERT(pListBox);  
  69.   
  70.     pListBox->strText = pszText;  
  71.     pListBox->fgColor = fgColor;  
  72.     pListBox->bgColor = bgColor;  
  73.   
  74.     m_sArray.push_back(pListBox);  
  75.   
  76.     return CListBox::AddString(pszText);  
  77. }  
  78.   
  79. void CMultiLineListBox::AddSubString(int nIndex, LPCTSTR pszText, COLORREF fgColor, COLORREF bgColor)  
  80. {  
  81.     ASSERT((nIndex >=0) && (nIndex < GetCount()));  
  82.       
  83.     ASSERT(!m_sArray.empty());  
  84.   
  85.     LISTBOXINFO* pListBox = m_sArray.at(nIndex);  
  86.     ASSERT(pListBox);  
  87.   
  88.     LISTBOXINFO::SUBNODEINFO* pSubNode = new LISTBOXINFO::SUBNODEINFO;  
  89.     ASSERT(pSubNode);  
  90.   
  91.     pSubNode->strText = pszText;  
  92.     pSubNode->fgColor = fgColor;  
  93.     pSubNode->bgColor = bgColor;  
  94.     pListBox->subArray.push_back(pSubNode);  
  95. }  
  96.   
  97. // CMultiLineListBox message handlers  
  98.   
  99. void CMultiLineListBox::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)  
  100. {  
  101.     // TODO:  Add your code to determine the size of specified item  
  102.     ASSERT(lpMeasureItemStruct->CtlType == ODT_LISTBOX);  
  103.   
  104.     lpMeasureItemStruct->itemHeight = ITEM_HEIGHT;  
  105. }  
  106.   
  107. void CMultiLineListBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)  
  108. {  
  109.     // TODO:  Add your code to draw the specified item  
  110.     ASSERT(lpDrawItemStruct->CtlType == ODT_LISTBOX);  
  111.   
  112.     int nIndex = lpDrawItemStruct->itemID;  
  113.   
  114.     if((!m_sArray.empty())  && (nIndex < static_cast<int>(m_sArray.size())))  
  115.     {  
  116.         CDC dc;  
  117.         dc.Attach(lpDrawItemStruct->hDC);  
  118.   
  119.         // Save these value to restore them when done drawing.  
  120.         COLORREF crOldTextColor = dc.GetTextColor();  
  121.         COLORREF crOldBkColor = dc.GetBkColor();  
  122.   
  123.         // If this item is selected, set the background color   
  124.         // and the text color to appropriate values. Also, erase  
  125.         // rect by filling it with the background color.  
  126.         CRect rc(lpDrawItemStruct->rcItem);  
  127.           
  128.         LISTBOXINFO* pListBox = m_sArray.at(nIndex);  
  129.         ASSERT(pListBox);  
  130.   
  131.         if ((lpDrawItemStruct->itemAction | ODA_SELECT) &&  
  132.             (lpDrawItemStruct->itemState & ODS_SELECTED))  
  133.         {  
  134.             dc.SetTextColor(pListBox->bgColor);  
  135.             dc.SetBkColor(pListBox->fgColor);  
  136.             dc.FillSolidRect(&rc, pListBox->fgColor);  
  137.   
  138.             // Draw item the text.  
  139.             CRect rect(rc);  
  140.             int nItemCount = 1;  
  141.             nItemCount += static_cast<int>(pListBox->subArray.size());  
  142.             int nItemHeight = rc.Height() / nItemCount;  
  143.             rect.bottom = rect.top + nItemHeight;  
  144.             dc.DrawText(pListBox->strText, pListBox->strText.GetLength(), CRect(rect.left + 5, rect.top, rect.right, rect.bottom), DT_SINGLELINE | DT_VCENTER);  
  145.               
  146.             // Draw subitem the text.  
  147.             CRect rcItem;  
  148.             rcItem.SetRectEmpty();  
  149.             rcItem.top = rect.bottom;  
  150.             rcItem.left = rect.left;  
  151.             rcItem.right = rect.right;  
  152.             rcItem.bottom = rcItem.top + nItemHeight;  
  153.               
  154.             vector<LISTBOXINFO::SUBNODEINFO*>::const_iterator iter = pListBox->subArray.begin();  
  155.             for(; iter != pListBox->subArray.end(); ++iter)  
  156.             {  
  157.                 LISTBOXINFO::SUBNODEINFO* pSubNode = *iter;  
  158.                 dc.SetTextColor(pSubNode->fgColor);  
  159.                 dc.SetBkColor(pSubNode->bgColor);  
  160.                 dc.FillSolidRect(&rcItem, pSubNode->bgColor);  
  161.   
  162.                 CRect rectItem(rcItem);  
  163.                 rectItem.left += 22;  
  164.                 dc.DrawText(pSubNode->strText, pSubNode->strText.GetLength(), &rectItem, DT_SINGLELINE | DT_VCENTER);  
  165.                   
  166.                 rcItem.top = rcItem.bottom;  
  167.                 rcItem.bottom = rcItem.top + nItemHeight;  
  168.             }  
  169.   
  170.             dc.DrawFocusRect(rc);   // Draw focus rect  
  171.         }  
  172.         else  
  173.         {  
  174.             dc.SetTextColor(pListBox->fgColor);  
  175.             dc.SetBkColor(pListBox->bgColor);  
  176.             dc.FillSolidRect(&rc, pListBox->bgColor);  
  177.   
  178.             // Draw the text.  
  179.             CRect rect(rc);  
  180.             rect.left += 5;  
  181.             dc.DrawText(pListBox->strText, pListBox->strText.GetLength(), &rect, DT_SINGLELINE | DT_VCENTER);  
  182.         }  
  183.   
  184.         // Reset the background color and the text color back to their  
  185.         // original values.  
  186.         dc.SetTextColor(crOldTextColor);  
  187.         dc.SetBkColor(crOldBkColor);  
  188.   
  189.         dc.Detach();  
  190.     }  
  191. }  
  192.   
  193. BOOL CMultiLineListBox::OnEraseBkgnd(CDC* pDC)  
  194. {  
  195.     // Set listbox background color  
  196.     CRect rc;  
  197.     GetClientRect(&rc);  
  198.       
  199.     CDC memDC;  
  200.     memDC.CreateCompatibleDC(pDC);  
  201.     ASSERT(memDC.GetSafeHdc());  
  202.   
  203.     CBitmap bmp;  
  204.     bmp.CreateCompatibleBitmap(pDC, rc.Width(), rc.Height());  
  205.     ASSERT(bmp.GetSafeHandle());  
  206.   
  207.     CBitmap* pOldbmp = (CBitmap*)memDC.SelectObject(&bmp);  
  208.   
  209.     memDC.FillSolidRect(rc, LISTBOX_BACKGROUND); // Set background color which you want  
  210.     pDC->BitBlt(0, 0, rc.Width(), rc.Height(), &memDC, 0, 0, SRCCOPY);  
  211.   
  212.     memDC.SelectObject(pOldbmp);  
  213.     bmp.DeleteObject();  
  214.     memDC.DeleteDC();  
  215.   
  216.     return TRUE;  
  217. }  
  218.   
  219. void CMultiLineListBox::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)  
  220. {  
  221.     // TODO: Add your message handler code here and/or call default  
  222.     CListBox::OnKeyDown(nChar, nRepCnt, nFlags);  
  223.   
  224.     UpdateItem();  
  225. }  
  226.   
  227. void CMultiLineListBox::OnLButtonDown(UINT nFlags, CPoint point)  
  228. {  
  229.     // TODO: Add your message handler code here and/or call default  
  230.     CListBox::OnLButtonDown(nFlags, point);  
  231.   
  232.     UpdateItem();  
  233. }  
  234.   
  235. void CMultiLineListBox::OnMouseMove(UINT nFlags, CPoint point)  
  236. {  
  237.     // TODO: Add your message handler code here and/or call default  
  238.     CListBox::OnMouseMove(nFlags, point);  
  239.   
  240.     UpdateItem();  
  241. }  
  242.   
  243. void CMultiLineListBox::UpdateItem()  
  244. {  
  245.     // If per item height not equal, you must calculate area between the current focus item with last one,  
  246.     // otherwise you must calculate area between the current focus item with previously focus item.  
  247.     int nIndex = GetCurSel();  
  248.     if((CB_ERR != nIndex) && (m_nFocusIndex != nIndex))  
  249.     {  
  250.         PostMessage(MSG_UPDATEITEM, (WPARAM)m_nFocusIndex, (LPARAM)nIndex);  
  251.         m_nFocusIndex = nIndex; // Set current select focus index  
  252.     }  
  253. }  
  254.   
  255. LRESULT CMultiLineListBox::OnUpdateItem(WPARAM wParam, LPARAM lParam)  
  256. {  
  257.     int nPreIndex = static_cast<int>(wParam);  
  258.     int nCurIndex = static_cast<int>(lParam);  
  259.   
  260.     if(-1 != nPreIndex)  
  261.     {  
  262.         SetItemHeight(nPreIndex, ITEM_HEIGHT);  
  263.     }  
  264.       
  265.     if(-1 != nCurIndex)  
  266.     {  
  267.         int nItemCount = 1;  
  268.         LISTBOXINFO* pListBox = m_sArray.at(nCurIndex);  
  269.         ASSERT(pListBox);  
  270.         nItemCount += static_cast<int>(pListBox->subArray.size());  
  271.         SetItemHeight(nCurIndex, ITEM_HEIGHT * nItemCount);  
  272.     }  
  273.   
  274.     Invalidate(); // Update item  
  275.     return 0;  
  276. }  

  1. // 调用方法  
  2. // 成员变量,关联了CListBox窗口对象  
  3. CMultiLineListBox m_listBox;   
  4. // 资源编辑CListBox属性设置Owner Draw: Variable, Selection: Single, Has Strings: TRUE  
  5.   
  6. // 主对话框的OnInitDialog函数中设置  
  7. COLORREF clr[][2] =   
  8.     {  
  9.         {RGB(53, 0, 27), RGB(236, 255, 236)},  
  10.         {RGB(66, 0, 33), RGB(233, 255, 233)},  
  11.         {RGB(85, 0, 43), RGB(204, 255, 204)},  
  12.         {RGB(106, 0, 53), RGB(191, 255, 191)},  
  13.         {RGB(119, 0, 60), RGB(9, 255, 9)},  
  14.         {RGB(136, 0, 68), RGB(0, 236, 0)},  
  15.         {RGB(155, 0, 78), RGB(0, 225, 0)},  
  16.         {RGB(168, 0, 84), RGB(0, 204, 0)},  
  17.         {RGB(170, 0, 85), RGB(0, 185, 0)},  
  18.         {RGB(187, 0, 94), RGB(0, 170, 0)},  
  19.         {RGB(206, 0, 103), RGB(0, 151, 0)},  
  20.         {RGB(211, 0, 111), RGB(0, 136, 0)},  
  21.         {RGB(236, 0, 118), RGB(0, 117, 0)},  
  22.         {RGB(255, 108, 182), RGB(0, 98, 0)},  
  23.         {RGB(255, 121, 188), RGB(0, 89, 0)},  
  24.         {RGB(255, 138, 197), RGB(0, 70, 0)},  
  25.         {RGB(255, 157, 206), RGB(0, 53, 0)},  
  26.         {RGB(255, 170, 212), RGB(0, 36, 0)},  
  27.         {RGB(255, 193, 224), RGB(0, 21, 0)}  
  28.     };  
  29.   
  30.     CString strText(_T(""));  
  31.     int nIndex = -1;  
  32.     for(int i=0; i<sizeof(clr)/sizeof(clr[0]); i++)  
  33.     {  
  34.         strText.Format(_T("%02d - Hello, World!"), i+1);  
  35.   
  36.         nIndex = m_listBox.AddString(strText, clr[i][0], clr[i][1]);  
  37.         if(i % 2)  
  38.         {  
  39.             for(int j=0; j<3; j++)  
  40.             {  
  41.                 strText.Format(_T("%02d.%02d - Hello, World!"), i+1, j+1);  
  42.                 m_listBox.AddSubString(nIndex, strText, clr[i][1], clr[i][0]);  
  43.             }  
  44.         }  
  45.         else  
  46.         {  
  47.             for(int j=0; j<2; j++)  
  48.             {  
  49.                 strText.Format(_T("%02d.%02d - Hello, World!"), i+1, j+1);  
  50.                 m_listBox.AddSubString(nIndex, strText, clr[i][1], clr[i][0]);  
  51.             }  
  52.         }  
  53.     }  

运行效果图如下所示:



微信小程序扫码登陆

文章评论

1194人参与,0条评论