Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

Store and show Tree struct in a Combobox

, 31 Jul 2002
Store and show Tree struct in Combobox
cwzcombox_demo.zip
cwzcombox_src.zip
testcbx
res
small2.ico
small3.ico
small4.ico
small5.ico
studio18c.BMP
testcbx.ico
testcbx.clw
testcbx.dsp
testcbx.dsw
testcbx.log
//	CCWzComboBox.cpp : implementation file
/*********************************************************************
*	Author:		Simon Wang
*	Date:		2002-06-21
*	Contact us:	Inte2000@263.net
**********************************************************************/
#include "stdafx.h"
#include "testcbx.h"
#include "WzComboBox.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CWzComboBox

CWzComboBox::CWzComboBox()
{
	m_crBkGnd = ::GetSysColor(COLOR_WINDOW);
	m_crHiLightBkGnd = ::GetSysColor(COLOR_HIGHLIGHT);
	m_crText = ::GetSysColor(COLOR_WINDOWTEXT);
	m_crHiLightText = ::GetSysColor(COLOR_HIGHLIGHTTEXT);
	m_crHiLightFrame = RGB(0,0,0);

	VERIFY(m_ImgList.Create(16,16,ILC_COLOR8|ILC_MASK,2,1));
}

CWzComboBox::~CWzComboBox()
{
	if(m_ImgList.GetSafeHandle() != NULL)
		m_ImgList.DeleteImageList();
}


BEGIN_MESSAGE_MAP(CWzComboBox, CComboBox)
	//{{AFX_MSG_MAP(CWzComboBox)
	ON_CONTROL_REFLECT(CBN_DROPDOWN, OnDropdown)
	ON_WM_PAINT()
	ON_WM_SYSCOLORCHANGE()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CWzComboBox message handlers
void CWzComboBox::OnDropdown() 
{
	RecalcDropWidth();
}

/***************************Virtual Function***************************************************/
void CWzComboBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) 
{
	ASSERT(lpDrawItemStruct != NULL);
	ASSERT(lpDrawItemStruct->CtlType == ODT_COMBOBOX);	
	if(int(lpDrawItemStruct->itemID) < 0)
		return;

	CDC* pDC   = CDC::FromHandle(lpDrawItemStruct->hDC);

  if (!IsWindowEnabled()) 
	{
		pDC->FillSolidRect(&lpDrawItemStruct->rcItem,RGB(192,192,192));
    pDC->SetBkMode(TRANSPARENT);
    pDC->SetTextColor(::GetSysColor(COLOR_WINDOWTEXT));

		DrawIconString(lpDrawItemStruct, FALSE);
    
    return;
  }

  // Selected
  if ((lpDrawItemStruct->itemState & ODS_SELECTED) && (lpDrawItemStruct->itemAction & (ODA_SELECT | ODA_DRAWENTIRE))) 
	{
		pDC->FillSolidRect(&lpDrawItemStruct->rcItem,m_crBkGnd);
    pDC->SetBkMode(TRANSPARENT);
    pDC->SetTextColor(m_crHiLightText);
    
		DrawIconString(lpDrawItemStruct, TRUE);
    
  }

  // De-Selected
  if (!(lpDrawItemStruct->itemState & ODS_SELECTED) && (lpDrawItemStruct->itemAction & (ODA_SELECT | ODA_DRAWENTIRE))) 
	{
		pDC->FillSolidRect(&lpDrawItemStruct->rcItem,m_crBkGnd);
    pDC->SetBkMode(TRANSPARENT);
    pDC->SetTextColor(m_crText);
    
		DrawIconString(lpDrawItemStruct, FALSE);
  }

}

void CWzComboBox::DrawIconString(LPDRAWITEMSTRUCT lpDIS, BOOL bselected)
{
	CDC* pDC = CDC::FromHandle(lpDIS->hDC);
	LPITEMDATA pData= (LPITEMDATA)GetItemData(lpDIS->itemID);
	CRect rcText(lpDIS->rcItem);
	rcText.right -= 1;//space for right border

	if (m_ImgList.GetImageCount() > 0)//has icon attach
	{
		POINT pt;
		CRect rcIcon;

		TRACE(_T("itemState = %d, itemAction = %d\n"),lpDIS->itemState,lpDIS->itemAction);

//@**#---2002-07-21 22:10:05 (Simon)---#**@
//#ifdef _WIN2K_CHINESE_SP2
//		if(lpDIS->itemState == ODS_COMBOBOXEDIT && lpDIS->itemAction == ODA_DRAWENTIRE)//4096
//			rcIcon.left = rcText.left + 2;
//		else if(lpDIS->itemState == (ODS_FOCUS|ODS_COMBOBOXEDIT|ODS_SELECTED) && lpDIS->itemAction == ODA_DRAWENTIRE)//4113
//			rcIcon.left = rcText.left + 2;
//#else //_WIN2K_ENGLISH_SP3
//		if(lpDIS->itemState == 4864 && lpDIS->itemAction == 1)
//			rcIcon.left = rcText.left + 2;
//		else if(lpDIS->itemState == 4881 && lpDIS->itemAction == 1)//4113
//			rcIcon.left = rcText.left + 2;
//#endif

		if((lpDIS->itemState & ODS_COMBOBOXEDIT) && lpDIS->itemAction == ODA_DRAWENTIRE)
			rcIcon.left = rcText.left + 2;
		else
			rcIcon.left = rcText.left + pData->cLevel * 20;//20 = 18+2
		rcIcon.top = rcText.top;
		rcIcon.bottom = rcText.bottom;
		rcIcon.right = rcIcon.left + 18;

		pt.x = rcIcon.left + 2;
		pt.y = rcIcon.top;
    m_ImgList.Draw(pDC,pData->cType,pt,ILD_TRANSPARENT);
		if(bselected)
		{
			rcIcon.InflateRect(0,0,1,0);
			pDC->Draw3dRect(rcIcon,RGB(255,128,128),RGB(0,0,255));
		}
		rcText.left = rcIcon.right+2;
	}

	CString string = _T(""); 
	if (lpDIS->itemID != -1) 
		GetLBText(lpDIS->itemID, string);

	if(bselected)
	{
		pDC->FillSolidRect(&rcText,m_crHiLightBkGnd);
		CPen penFrame(PS_SOLID, 1, m_crHiLightFrame);
		CPen *pOP = pDC->SelectObject(&penFrame);
		pDC->SelectStockObject(NULL_BRUSH);
		pDC->Rectangle(&rcText);
		pDC->SelectObject(pOP);
		penFrame.DeleteObject();
	}

	rcText.DeflateRect(3,1,2,1);
  pDC->DrawText(string, rcText, DT_SINGLELINE |DT_VCENTER ); 
}   

void CWzComboBox::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct) 
{
	ASSERT(lpMeasureItemStruct->CtlType == ODT_COMBOBOX);

	lpMeasureItemStruct->itemHeight = 18;//Icon 16X16
}

void CWzComboBox::DeleteItem(LPDELETEITEMSTRUCT lpDeleteItemStruct) 
{
	ASSERT(lpDeleteItemStruct->CtlType == ODT_COMBOBOX);
	LPITEMDATA pData = (LPITEMDATA)GetItemData(lpDeleteItemStruct->itemID);
	delete pData;//release our data 
	CComboBox::DeleteItem(lpDeleteItemStruct);
}

void CWzComboBox::PreSubclassWindow() 
{
	CComboBox::PreSubclassWindow();

  ::SendMessage(m_hWnd, CB_SETITEMHEIGHT, (WPARAM)-1, 16L);//use 16X16 size icon
}

/***************************Owner Function****************************************************/
int CWzComboBox::AddIcon(HICON hIcon)
{
	ASSERT(hIcon != NULL);

	return m_ImgList.Add(hIcon);//index = 0
}

WORD CWzComboBox::AddCTString(WORD wParentIdx,BYTE cType,LPCTSTR lpszString)
{
	int idx = -1;
	if(wParentIdx == nRootIndex)//if root node,just Add to the end of String List
	{
		idx = CComboBox::AddString(lpszString);//InsertString is not a virtual function
		LPITEMDATA pData = new ITEMDATA;
		ASSERT(pData != NULL);
		pData->cLevel = 0;
		pData->cType = cType;
		pData->wOriginIdx = (WORD)idx;
		pData->wParantOriginIdx = wParentIdx;
		SetItemData(idx,(DWORD)pData);
	}
	else
	{
		int ParentCurrentIdx = CurrentIdxFromOriginIdx((int)wParentIdx);
		LPITEMDATA pParentData = (LPITEMDATA)GetItemData(ParentCurrentIdx);
		int count = GetChildCount(pParentData->wOriginIdx);//Get All children node,include children's children node
		int pos = wParentIdx + count + 1;
		idx = CComboBox::InsertString(pos,lpszString);//InsertString is not a virtual function
		LPITEMDATA pData = new ITEMDATA;
		ASSERT(pData != NULL);
		pData->cLevel = pParentData->cLevel + 1;
		pData->cType = cType;
		pData->wOriginIdx = (WORD)idx;
		pData->wParantOriginIdx = pParentData->wOriginIdx;
		SetItemData(idx,(DWORD)pData);
	}

	return (WORD)idx;
}
//delete a item and all children item,return the remain node of Combox
int CWzComboBox::DeleteCTString(int index)
{
	LPITEMDATA pdata = (LPITEMDATA)GetItemData(index);
	BOOL bFind = TRUE;
	//delete all children nodes of this node
	while(bFind)
	{
		bFind = FALSE;//finish mark
		int count = GetCount();//get total items
		for(int i = index + 1; i < count; i++)//search from index+1
		{
			LPITEMDATA p = (LPITEMDATA)GetItemData(i);
			if(p->cLevel > pdata->cLevel)//children nodes' cLevel is higher than parent's node
			{
				bFind = TRUE;//find a children node,maybe more,so...
				CComboBox::DeleteString(i);
				break;
			}
		}
	}
	//delete this node at last
	CComboBox::DeleteString(index);
	return GetCount();
}

//Get All children node,include children's children node
int CWzComboBox::GetChildCount(WORD wParentIdx)
{
	LPITEMDATA pdata = (LPITEMDATA)GetItemData(wParentIdx);
	int nTotalCount = GetCount();
	int wChildCount = 0;
	for(int i = wParentIdx+1; i < nTotalCount; i++)
	{
		LPITEMDATA p = (LPITEMDATA)GetItemData(i);
		if(p->cLevel > pdata->cLevel)//children nodes' cLevel is higher than parent's node
			wChildCount++;
		else
			break;
	}

	return wChildCount;
}

//get node is current index by search original index
int CWzComboBox::CurrentIdxFromOriginIdx(int wOriginIdx)
{
	int nRtn = -1;
	int count = GetCount();
	for(int i = 0; i < count; i++)
	{
		LPITEMDATA pData = (LPITEMDATA)GetItemData(i);
		if(wOriginIdx == (int)pData->wOriginIdx)
		{
			nRtn = i;
			break;
		}
	}

	return nRtn;
}

void CWzComboBox::RecalcDropWidth()
{
	int nNumEntries = GetCount();
	int nWidth = 0;
	CString str;

//@**#---2002-06-26 16:58:48 (Simon)---#**@
//	CClientDC dc(this);
//	int nSave = dc.SaveDC();
//	dc.SelectObject(GetFont());

	CDC *pDC = GetDC();
	int nScrollWidth = ::GetSystemMetrics(SM_CXVSCROLL);
	for (int i = 0; i < nNumEntries; i++)
	{
		GetLBText(i, str);
		LPITEMDATA pData = (LPITEMDATA)GetItemData(i);
		int nLength = 20 + pData->cLevel * 8 + pDC->GetTextExtent(str).cx + nScrollWidth + 30;
//@**#---2002-06-26 17:06:08 (orbit)---#**@
//		SIZE size;
//		::GetTextExtentPoint32(pDC->GetSafeHdc(),str,str.GetLength(),&size);
//		int nLength = 20 + pData->cLevel * 8 + size.cx + nScrollWidth;
		nWidth = max(nWidth, nLength);
	}

	// Add margin space to the calculations
	nWidth += pDC->GetTextExtent("0").cx;

//	dc.RestoreDC(nSave);
	ReleaseDC(pDC);

	SetDroppedWidth(nWidth);
}

void CWzComboBox::DrawCombo(DWORD dwStyle, COLORREF clrTopLeft, COLORREF clrBottomRight)
{
	CRect rcItem;
	GetClientRect(&rcItem);
	CDC* pDC = GetDC();
	
	// Cover up dark 3D shadow.
	pDC->Draw3dRect(rcItem, clrTopLeft, clrBottomRight);
	rcItem.DeflateRect(1,1);
	
	if (!IsWindowEnabled()) 
	{
		pDC->Draw3dRect(rcItem, ::GetSysColor(COLOR_BTNHIGHLIGHT),::GetSysColor(COLOR_BTNHIGHLIGHT));
	}
	
	else 
	{
		pDC->Draw3dRect(rcItem, ::GetSysColor(COLOR_BTNFACE),::GetSysColor(COLOR_BTNFACE));
	}

	// Cover up dark 3D shadow on drop arrow.
	rcItem.DeflateRect(1,1);
	rcItem.left = rcItem.right-::GetSystemMetrics(SM_CXHTHUMB);//Offset();
	pDC->Draw3dRect(rcItem, ::GetSysColor(COLOR_BTNFACE),::GetSysColor(COLOR_BTNFACE));
	
	// Cover up normal 3D shadow on drop arrow.
	rcItem.DeflateRect(1,1);
	pDC->Draw3dRect(rcItem, ::GetSysColor(COLOR_BTNFACE),::GetSysColor(COLOR_BTNFACE));
	
	if (!IsWindowEnabled()) 
	{
		return;
	}

	switch (dwStyle)
	{
	case FC_DRAWNORMAL:
		rcItem.top -= 1;
		rcItem.bottom += 1;
		pDC->Draw3dRect(rcItem, ::GetSysColor(COLOR_BTNHIGHLIGHT),::GetSysColor(COLOR_BTNHIGHLIGHT));
		rcItem.left -= 1;
		pDC->Draw3dRect(rcItem, ::GetSysColor(COLOR_BTNHIGHLIGHT),::GetSysColor(COLOR_BTNHIGHLIGHT));
		break;

	case FC_DRAWRAISED:
		rcItem.top -= 1;
		rcItem.bottom += 1;
		pDC->Draw3dRect(rcItem, ::GetSysColor(COLOR_BTNHIGHLIGHT),::GetSysColor(COLOR_BTNSHADOW));
		break;

	case FC_DRAWPRESSD:
		rcItem.top -= 1;
		rcItem.bottom += 1;
		rcItem.OffsetRect(1,1);
		pDC->Draw3dRect(rcItem, ::GetSysColor(COLOR_BTNSHADOW),::GetSysColor(COLOR_BTNHIGHLIGHT));
		break;
	}

	ReleaseDC(pDC);
}
  
void CWzComboBox::OnPaint() 
{
	Default();
	DrawCombo(FC_DRAWRAISED, ::GetSysColor(COLOR_BTNSHADOW),::GetSysColor(COLOR_BTNHIGHLIGHT));
}

void CWzComboBox::OnSysColorChange() 
{
	CComboBox::OnSysColorChange();

	m_crBkGnd = ::GetSysColor(COLOR_WINDOW);
	m_crHiLightBkGnd = ::GetSysColor(COLOR_HIGHLIGHT);
	m_crText = ::GetSysColor(COLOR_WINDOWTEXT);
	m_crHiLightText = ::GetSysColor(COLOR_HIGHLIGHTTEXT);
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)

About the Author

Simon.W
Software Developer (Senior)
China China
I had graduated from HuaZhong University of Science & Technology. Now, I'm working in ZTE.

| Advertise | Privacy | Mobile
Web03 | 2.8.140721.1 | Last Updated 1 Aug 2002
Article Copyright 2002 by Simon.W
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid