返回> 网站首页
简单的自绘CListBox(三)(类似CTreeCtrl Expand效果)
yoours2011-03-23 13:43:28
简介一边听听音乐,一边写写文章。
一个简单的扩展的CListBox类,点击某一个item的时候,自动展开该项来显示更多信息,类似CTreeCtrl控件的Expand样式风格。
- // H 文件
- #pragma once
- #include <vector>
- 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<SUBNODEINFO*> 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<LISTBOXINFO*> 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()
- };
- // 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<LISTBOXINFO*>::const_iterator iter1 = m_sArray.begin();
- for(; iter1 != m_sArray.end(); ++iter1)
- {
- LISTBOXINFO* pNode = *iter1;
- vector<LISTBOXINFO::SUBNODEINFO*>::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<int>(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<int>(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<LISTBOXINFO::SUBNODEINFO*>::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<int>(wParam);
- int nCurIndex = static_cast<int>(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<int>(pListBox->subArray.size());
- SetItemHeight(nCurIndex, ITEM_HEIGHT * nItemCount);
- }
- Invalidate(); // Update item
- return 0;
- }
- // 调用方法
- // 成员变量,关联了CListBox窗口对象
- CMultiLineListBox m_listBox;
- // 资源编辑CListBox属性设置Owner Draw: Variable, Selection: Single, Has Strings: TRUE
- // 主对话框的OnInitDialog函数中设置
- COLORREF clr[][2] =
- {
- {RGB(53, 0, 27), RGB(236, 255, 236)},
- {RGB(66, 0, 33), RGB(233, 255, 233)},
- {RGB(85, 0, 43), RGB(204, 255, 204)},
- {RGB(106, 0, 53), RGB(191, 255, 191)},
- {RGB(119, 0, 60), RGB(9, 255, 9)},
- {RGB(136, 0, 68), RGB(0, 236, 0)},
- {RGB(155, 0, 78), RGB(0, 225, 0)},
- {RGB(168, 0, 84), RGB(0, 204, 0)},
- {RGB(170, 0, 85), RGB(0, 185, 0)},
- {RGB(187, 0, 94), RGB(0, 170, 0)},
- {RGB(206, 0, 103), RGB(0, 151, 0)},
- {RGB(211, 0, 111), RGB(0, 136, 0)},
- {RGB(236, 0, 118), RGB(0, 117, 0)},
- {RGB(255, 108, 182), RGB(0, 98, 0)},
- {RGB(255, 121, 188), RGB(0, 89, 0)},
- {RGB(255, 138, 197), RGB(0, 70, 0)},
- {RGB(255, 157, 206), RGB(0, 53, 0)},
- {RGB(255, 170, 212), RGB(0, 36, 0)},
- {RGB(255, 193, 224), RGB(0, 21, 0)}
- };
- CString strText(_T(""));
- int nIndex = -1;
- for(int i=0; i<sizeof(clr)/sizeof(clr[0]); i++)
- {
- strText.Format(_T("%02d - Hello, World!"), i+1);
- nIndex = m_listBox.AddString(strText, clr[i][0], clr[i][1]);
- if(i % 2)
- {
- for(int j=0; j<3; j++)
- {
- strText.Format(_T("%02d.%02d - Hello, World!"), i+1, j+1);
- m_listBox.AddSubString(nIndex, strText, clr[i][1], clr[i][0]);
- }
- }
- else
- {
- for(int j=0; j<2; j++)
- {
- strText.Format(_T("%02d.%02d - Hello, World!"), i+1, j+1);
- m_listBox.AddSubString(nIndex, strText, clr[i][1], clr[i][0]);
- }
- }
- }
运行效果图如下所示:
文章评论
1491人参与,0条评论