西贝尔凯基莉十三部:简单的自绘CListBox(三)(类似CTreeCtrl Expand效果)

来源:百度文库 编辑:九乡新闻网 时间:2024/04/27 21:43:11

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

view plaincopy to clipboardprint?
01.// H 文件  
02. 
03.#pragma once  
04. 
05.#include   
06.using namespace std;  
07.// CMultiLineListBox  
08. 
09.#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 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 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.}; 
// H 文件

#pragma once

#include
using namespace std;
// CMultiLineListBox

#define RGB_FOREGROUND RGB(0, 0, 0)
#define RGB_BACKGROUND RGB(255, 255, 255)
#define LISTBOX_BACKGROUND RGB(236, 255, 236)

class CMultiLineListBox : public CListBox
{
 DECLARE_DYNAMIC(CMultiLineListBox)

public:
 CMultiLineListBox();
 virtual ~CMultiLineListBox();

typedef struct _LISTBOX_INFO_
{
public:
 typedef struct _SUBNODE_INFO_
 {
 public:
  CString strText;
  COLORREF fgColor;
  COLORREF bgColor;

  _SUBNODE_INFO_()
  {
   clean();
  }
  ~_SUBNODE_INFO_()
  {
   clean();
  }
 protected:
  inline void clean(void)
  {
   strText.Empty();
   fgColor = RGB_FOREGROUND;
   bgColor = RGB_BACKGROUND;
  }
 }SUBNODEINFO, *PSUBNODEINFO;

public:
 vector subArray;
 CString strText;
 COLORREF fgColor;
 COLORREF bgColor;

 _LISTBOX_INFO_()
 {
  clean();
 }
 ~_LISTBOX_INFO_()
 {
  clean();
 }

protected:
 inline void clean(void)
 {
  subArray.clear();
  strText.Empty();
  fgColor = RGB_FOREGROUND;
  bgColor = RGB_BACKGROUND;
 }
}LISTBOXINFO, * PLISTBOXINFO;

protected:
 static int m_nFocusIndex;
 vector m_sArray;

public:
 int InsertString(int nIndex, LPCTSTR pszText, COLORREF fgColor = RGB_FOREGROUND, COLORREF bgColor = RGB_BACKGROUND);
 int AddString(LPCTSTR pszText, COLORREF fgColor = RGB_FOREGROUND, COLORREF bgColor = RGB_BACKGROUND);
 void AddSubString(int nIndex, LPCTSTR pszText, COLORREF fgColor = RGB_FOREGROUND, COLORREF bgColor = RGB_BACKGROUND);
 
protected:
 virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
 virtual void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct);
 void UpdateItem(void);
 void GetItemHeight(int nIndex);

protected:
 afx_msg BOOL OnEraseBkgnd(CDC* pDC);
 afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
 afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
 afx_msg void OnMouseMove(UINT nFlags, CPoint point);
 afx_msg LRESULT OnUpdateItem(WPARAM wParam, LPARAM lParam);

 DECLARE_MESSAGE_MAP()
};
 

view plaincopy to clipboardprint?
01.// CPP 文件  
02. 
03.// MultiLineListBox.cpp : implementation file  
04.//  
05. 
06.#include "stdafx.h"  
07.#include "MultiLineListBox.h"  
08. 
09.// 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::const_iterator iter1 = m_sArray.begin();  
25.    for(; iter1 != m_sArray.end(); ++iter1)  
26.    {  
27.        LISTBOXINFO* pNode = *iter1;  
28.        vector::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(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(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::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(wParam);  
258.    int nCurIndex = static_cast(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(pListBox->subArray.size());  
271.        SetItemHeight(nCurIndex, ITEM_HEIGHT * nItemCount);  
272.    }  
273. 
274.    Invalidate(); // Update item  
275.    return 0;  
276.} 
// CPP 文件

// MultiLineListBox.cpp : implementation file
//

#include "stdafx.h"
#include "MultiLineListBox.h"

// CMultiLineListBox
#define MSG_UPDATEITEM WM_USER + 0x1001
#define ITEM_HEIGHT 20

int CMultiLineListBox::m_nFocusIndex = -1;

IMPLEMENT_DYNAMIC(CMultiLineListBox, CListBox)

CMultiLineListBox::CMultiLineListBox()
{
 m_sArray.clear();
}

CMultiLineListBox::~CMultiLineListBox()
{
 vector::const_iterator iter1 = m_sArray.begin();
 for(; iter1 != m_sArray.end(); ++iter1)
 {
  LISTBOXINFO* pNode = *iter1;
  vector::const_iterator iter2 = pNode->subArray.begin();
  for(; iter2 != pNode->subArray.end(); ++iter2)
  {
   LISTBOXINFO::SUBNODEINFO* pSubNode = *iter2;
   delete pSubNode;
   pSubNode = NULL;
  }
  delete pNode;
  pNode = NULL;
 }
 m_sArray.clear();
}

BEGIN_MESSAGE_MAP(CMultiLineListBox, CListBox)
 ON_WM_ERASEBKGND()
 ON_WM_KEYDOWN()
 ON_WM_LBUTTONDOWN()
 ON_WM_MOUSEMOVE()
 ON_MESSAGE(MSG_UPDATEITEM, &CMultiLineListBox::OnUpdateItem)
END_MESSAGE_MAP()

int CMultiLineListBox::InsertString(int nIndex, LPCTSTR pszText, COLORREF fgColor, COLORREF bgColor)
{
 LISTBOXINFO* pListBox = new LISTBOXINFO;
 ASSERT(pListBox);

 ASSERT((nIndex >= 0) && (nIndex <= GetCount()));

 pListBox->strText = pszText;
 pListBox->fgColor = fgColor;
 pListBox->bgColor = bgColor;

 m_sArray.insert(m_sArray.begin() + nIndex, pListBox);

 return CListBox::InsertString(nIndex, pszText);
}

int CMultiLineListBox::AddString(LPCTSTR pszText, COLORREF fgColor, COLORREF bgColor)
{
 LISTBOXINFO* pListBox = new LISTBOXINFO;
 ASSERT(pListBox);

 pListBox->strText = pszText;
 pListBox->fgColor = fgColor;
 pListBox->bgColor = bgColor;

 m_sArray.push_back(pListBox);

 return CListBox::AddString(pszText);
}

void CMultiLineListBox::AddSubString(int nIndex, LPCTSTR pszText, COLORREF fgColor, COLORREF bgColor)
{
 ASSERT((nIndex >=0) && (nIndex < GetCount()));
 
 ASSERT(!m_sArray.empty());

 LISTBOXINFO* pListBox = m_sArray.at(nIndex);
 ASSERT(pListBox);

 LISTBOXINFO::SUBNODEINFO* pSubNode = new LISTBOXINFO::SUBNODEINFO;
 ASSERT(pSubNode);

 pSubNode->strText = pszText;
 pSubNode->fgColor = fgColor;
 pSubNode->bgColor = bgColor;
 pListBox->subArray.push_back(pSubNode);
}

// CMultiLineListBox message handlers

void CMultiLineListBox::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
 // TODO:  Add your code to determine the size of specified item
 ASSERT(lpMeasureItemStruct->CtlType == ODT_LISTBOX);

 lpMeasureItemStruct->itemHeight = ITEM_HEIGHT;
}

void CMultiLineListBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
 // TODO:  Add your code to draw the specified item
 ASSERT(lpDrawItemStruct->CtlType == ODT_LISTBOX);

 int nIndex = lpDrawItemStruct->itemID;

 if((!m_sArray.empty())  && (nIndex < static_cast(m_sArray.size())))
 {
  CDC dc;
  dc.Attach(lpDrawItemStruct->hDC);

  // Save these value to restore them when done drawing.
  COLORREF crOldTextColor = dc.GetTextColor();
  COLORREF crOldBkColor = dc.GetBkColor();

  // If this item is selected, set the background color
  // and the text color to appropriate values. Also, erase
  // rect by filling it with the background color.
  CRect rc(lpDrawItemStruct->rcItem);
  
  LISTBOXINFO* pListBox = m_sArray.at(nIndex);
  ASSERT(pListBox);

  if ((lpDrawItemStruct->itemAction | ODA_SELECT) &&
   (lpDrawItemStruct->itemState & ODS_SELECTED))
  {
   dc.SetTextColor(pListBox->bgColor);
   dc.SetBkColor(pListBox->fgColor);
   dc.FillSolidRect(&rc, pListBox->fgColor);

   // Draw item the text.
   CRect rect(rc);
   int nItemCount = 1;
   nItemCount += static_cast(pListBox->subArray.size());
   int nItemHeight = rc.Height() / nItemCount;
   rect.bottom = rect.top + nItemHeight;
   dc.DrawText(pListBox->strText, pListBox->strText.GetLength(), CRect(rect.left + 5, rect.top, rect.right, rect.bottom), DT_SINGLELINE | DT_VCENTER);
   
   // Draw subitem the text.
   CRect rcItem;
   rcItem.SetRectEmpty();
   rcItem.top = rect.bottom;
   rcItem.left = rect.left;
   rcItem.right = rect.right;
   rcItem.bottom = rcItem.top + nItemHeight;
   
   vector::const_iterator iter = pListBox->subArray.begin();
   for(; iter != pListBox->subArray.end(); ++iter)
   {
    LISTBOXINFO::SUBNODEINFO* pSubNode = *iter;
     dc.SetTextColor(pSubNode->fgColor);
     dc.SetBkColor(pSubNode->bgColor);
     dc.FillSolidRect(&rcItem, pSubNode->bgColor);

    CRect rectItem(rcItem);
    rectItem.left += 22;
    dc.DrawText(pSubNode->strText, pSubNode->strText.GetLength(), &rectItem, DT_SINGLELINE | DT_VCENTER);
    
    rcItem.top = rcItem.bottom;
    rcItem.bottom = rcItem.top + nItemHeight;
   }

   dc.DrawFocusRect(rc); // Draw focus rect
  }
  else
  {
   dc.SetTextColor(pListBox->fgColor);
   dc.SetBkColor(pListBox->bgColor);
   dc.FillSolidRect(&rc, pListBox->bgColor);

   // Draw the text.
   CRect rect(rc);
   rect.left += 5;
   dc.DrawText(pListBox->strText, pListBox->strText.GetLength(), &rect, DT_SINGLELINE | DT_VCENTER);
  }

  // Reset the background color and the text color back to their
  // original values.
  dc.SetTextColor(crOldTextColor);
  dc.SetBkColor(crOldBkColor);

  dc.Detach();
 }
}

BOOL CMultiLineListBox::OnEraseBkgnd(CDC* pDC)
{
 // Set listbox background color
 CRect rc;
 GetClientRect(&rc);
 
 CDC memDC;
 memDC.CreateCompatibleDC(pDC);
 ASSERT(memDC.GetSafeHdc());

 CBitmap bmp;
 bmp.CreateCompatibleBitmap(pDC, rc.Width(), rc.Height());
 ASSERT(bmp.GetSafeHandle());

 CBitmap* pOldbmp = (CBitmap*)memDC.SelectObject(&bmp);

 memDC.FillSolidRect(rc, LISTBOX_BACKGROUND); // Set background color which you want
 pDC->BitBlt(0, 0, rc.Width(), rc.Height(), &memDC, 0, 0, SRCCOPY);

 memDC.SelectObject(pOldbmp);
 bmp.DeleteObject();
 memDC.DeleteDC();

 return TRUE;
}

void CMultiLineListBox::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
 // TODO: Add your message handler code here and/or call default
 CListBox::OnKeyDown(nChar, nRepCnt, nFlags);

 UpdateItem();
}

void CMultiLineListBox::OnLButtonDown(UINT nFlags, CPoint point)
{
 // TODO: Add your message handler code here and/or call default
 CListBox::OnLButtonDown(nFlags, point);

 UpdateItem();
}

void CMultiLineListBox::OnMouseMove(UINT nFlags, CPoint point)
{
 // TODO: Add your message handler code here and/or call default
 CListBox::OnMouseMove(nFlags, point);

 UpdateItem();
}

void CMultiLineListBox::UpdateItem()
{
 // If per item height not equal, you must calculate area between the current focus item with last one,
 // otherwise you must calculate area between the current focus item with previously focus item.
 int nIndex = GetCurSel();
 if((CB_ERR != nIndex) && (m_nFocusIndex != nIndex))
 {
  PostMessage(MSG_UPDATEITEM, (WPARAM)m_nFocusIndex, (LPARAM)nIndex);
  m_nFocusIndex = nIndex; // Set current select focus index
 }
}

LRESULT CMultiLineListBox::OnUpdateItem(WPARAM wParam, LPARAM lParam)
{
 int nPreIndex = static_cast(wParam);
 int nCurIndex = static_cast(lParam);

 if(-1 != nPreIndex)
 {
  SetItemHeight(nPreIndex, ITEM_HEIGHT);
 }
 
 if(-1 != nCurIndex)
 {
  int nItemCount = 1;
  LISTBOXINFO* pListBox = m_sArray.at(nCurIndex);
  ASSERT(pListBox);
  nItemCount += static_cast(pListBox->subArray.size());
  SetItemHeight(nCurIndex, ITEM_HEIGHT * nItemCount);
 }

  Invalidate(); // Update item
 return 0;
}

view plaincopy to clipboardprint?
01.// 调用方法  
02.// 成员变量,关联了CListBox窗口对象  
03.CMultiLineListBox m_listBox;   
04.// 资源编辑CListBox属性设置Owner Draw: Variable, Selection: Single, Has Strings: TRUE  
05. 
06.// 主对话框的OnInitDialog函数中设置  
07.COLORREF clr[][2] =   
08.    {  
09.        {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; i33.    {  
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.    }