分享

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

 学海无涯GL 2013-10-18

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

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

 

// H 文件


#pragma once


#include <vector>

using namespace std;

// CMultiLineListBox


#define RGB_FOREGROUND #000000

#define RGB_BACKGROUND #ffffff

#define LISTBOX_BACKGROUND #ecffec


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] = 

{

{#35001b, #ecffec},

{#420021, #e9ffe9},

{#55002b, #ccffcc},

{#6a0035, #bfffbf},

{#77003c, #09ff09},

{#880044, #00ec00},

{#9b004e, #00e100},

{#a80054, #00cc00},

{#aa0055, #00b900},

{#bb005e, #00aa00},

{#ce0067, #009700},

{#d3006f, #008800},

{#ec0076, #007500},

{#ff6cb6, #006200},

{#ff79bc, #005900},

{#ff8ac5, #004600},

{#ff9dce, #003500},

{#ffaad4, #002400},

{#ffc1e0, #001500}

};


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]);

}

}

}

 

运行效果图如下所示:

 

 

 

 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多