www.pudn.com > ListCtrl功能扩展.rar > ComboListCtrl.cpp


/******************************************************************************* 
	Author						: Aravindan Premkumar 
	Unregistered Copyright 2003	: Aravindan Premkumar 
	All Rights Reserved 
	 
	This piece of code does not have any registered copyright and is free to be  
	used as necessary. The user is free to modify as per the requirements. As a 
	fellow developer, all that I expect and request for is to be given the  
	credit for intially developing this reusable code by not removing my name as  
	the author. 
*******************************************************************************/ 
 
#include "stdafx.h" 
#include "ComboListCtrl.h" 
#include "InplaceCombo.h" 
#include "InPlaceEdit.h" 
 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
 
//#defines 
#define FIRST_COLUMN				0 
#define MIN_COLUMN_WIDTH			10 
#define MAX_DROP_DOWN_ITEM_COUNT	10 
 
///////////////////////////////////////////////////////////////////////////// 
// CComboListCtrl 
 
CComboListCtrl::CComboListCtrl() 
{ 
	m_iColumnCounts = 0; 
	m_ComboSupportColumnsList.RemoveAll(); 
	m_ReadOnlyColumnsList.RemoveAll(); 
	m_strValidEditCtrlChars.Empty(); 
	m_dwEditCtrlStyle = ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_LEFT | ES_NOHIDESEL; 
	m_dwDropDownCtrlStyle = WS_BORDER | WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | ES_AUTOVSCROLL |  
		CBS_DROPDOWNLIST | CBS_DISABLENOSCROLL; 
} 
 
CComboListCtrl::~CComboListCtrl() 
{ 
	CInPlaceCombo::DeleteInstance(); 
	CInPlaceEdit::DeleteInstance();   
} 
 
 
BEGIN_MESSAGE_MAP(CComboListCtrl, CListCtrl) 
	//{{AFX_MSG_MAP(CComboListCtrl) 
	ON_WM_HSCROLL() 
	ON_WM_VSCROLL() 
	ON_WM_LBUTTONDOWN() 
	ON_NOTIFY_REFLECT(LVN_ENDLABELEDIT, OnEndLabelEdit) 
	ON_NOTIFY_REFLECT(LVN_BEGINLABELEDIT, OnBeginLabelEdit) 
	//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 
///////////////////////////////////////////////////////////////////////////// 
// CComboListCtrl message handlers 
 
CInPlaceCombo* CComboListCtrl::ShowInPlaceList(int iRowIndex, int iColumnIndex, CStringList& rComboItemsList,  
											   CString strCurSelecetion /*= ""*/, int iSel /*= -1*/) 
{ 
	// The returned obPointer should not be saved 
 
	// Make sure that the item is visible 
	if (!EnsureVisible(iRowIndex, TRUE)) 
	{ 
		return NULL; 
	} 
 
	// Make sure that iColumnIndex is valid  
	CHeaderCtrl* pHeader = static_cast (GetDlgItem(FIRST_COLUMN)); 
 
	int iColumnCount = pHeader->GetItemCount(); 
 
	if (iColumnIndex >= iColumnCount || GetColumnWidth(iColumnIndex) < MIN_COLUMN_WIDTH)  
	{ 
		return NULL; 
	} 
 
	// Calculate the rectangle specifications for the combo box 
	CRect obCellRect(0, 0, 0, 0); 
	CalculateCellRect(iColumnIndex, iRowIndex, obCellRect); 
 
	int iHeight = obCellRect.Height();   
	int iCount = (int )rComboItemsList.GetCount(); 
 
	iCount = (iCount < MAX_DROP_DOWN_ITEM_COUNT) ?  
		iCount + MAX_DROP_DOWN_ITEM_COUNT : (MAX_DROP_DOWN_ITEM_COUNT + 1);  
 
	obCellRect.bottom += iHeight * iCount;  
 
	// Create the in place combobox 
	CInPlaceCombo* pInPlaceCombo = CInPlaceCombo::GetInstance(); 
	pInPlaceCombo->ShowComboCtrl(m_dwDropDownCtrlStyle, obCellRect, this, 0, iRowIndex, iColumnIndex, &rComboItemsList,  
		strCurSelecetion, iSel); 
 
	return pInPlaceCombo; 
} 
 
CInPlaceEdit* CComboListCtrl::ShowInPlaceEdit(int iRowIndex, int iColumnIndex, CString& rstrCurSelection) 
{ 
	// Create an in-place edit control 
	CInPlaceEdit* pInPlaceEdit = CInPlaceEdit::GetInstance(); 
 
	CRect obCellRect(0, 0, 0, 0); 
	CalculateCellRect(iColumnIndex, iRowIndex, obCellRect); 
 
	pInPlaceEdit->ShowEditCtrl(m_dwEditCtrlStyle, obCellRect, this, 0,  
		iRowIndex, iColumnIndex, 
		m_strValidChars[iColumnIndex], rstrCurSelection); 
 
	return pInPlaceEdit; 
} 
 
void CComboListCtrl::OnHScroll(UINT iSBCode, UINT iPos, CScrollBar* pScrollBar)  
{ 
	// TODO: Add your message handler code here and/or call default 
 
	if (GetFocus() != this) 
	{ 
		SetFocus(); 
	} 
 
	CListCtrl::OnHScroll(iSBCode, iPos, pScrollBar); 
} 
 
void CComboListCtrl::OnVScroll(UINT iSBCode, UINT iPos, CScrollBar* pScrollBar)  
{ 
	// TODO: Add your message handler code here and/or call default 
 
	if (GetFocus() != this) 
	{ 
		SetFocus(); 
	} 
 
	CListCtrl::OnVScroll(iSBCode, iPos, pScrollBar); 
} 
 
void CComboListCtrl::OnLButtonDown(UINT iFlags, CPoint obPoint)  
{ 
	// TODO: Add your message handler code here and/or call default 
 
	int iColumnIndex = -1; 
	int iRowIndex = -1; 
 
	// Get the current column and row 
	if (!HitTestEx(obPoint, &iRowIndex, &iColumnIndex)) 
	{ 
		return; 
	} 
 
	CListCtrl::OnLButtonDown(iFlags, obPoint); 
 
	// If column is not read only then 
	// If the SHIFT or CTRL key is down call the base class 
	// Check the high bit of GetKeyState to determine whether SHIFT or CTRL key is down 
	if ((GetKeyState(VK_SHIFT) & 0x80) || (GetKeyState(VK_CONTROL) & 0x80)) 
	{ 
		return; 
	} 
 
	// Get the current selection before creating the in place combo box 
	CString strCurSelection = GetItemText(iRowIndex, iColumnIndex); 
 
	if (-1 != iRowIndex) 
	{ 
		UINT flag = LVIS_FOCUSED; 
 
		if ((GetItemState(iRowIndex, flag ) & flag) == flag) 
		{ 
			// Add check for LVS_EDITLABELS 
			if (GetWindowLong(m_hWnd, GWL_STYLE) & LVS_EDITLABELS) 
			{ 
				// If combo box is supported 
				// Create and show the in place combo box 
				if (IsCombo(iColumnIndex)) 
				{ 
					CStringList obComboItemsList; 
 
					GetParent()->SendMessage(WM_SET_ITEMS, (WPARAM)iColumnIndex, (LPARAM)&obComboItemsList);   
 
					CInPlaceCombo* pInPlaceComboBox = ShowInPlaceList(iRowIndex, iColumnIndex, obComboItemsList, strCurSelection); 
					ASSERT(pInPlaceComboBox);  
 
					// Set the selection to previous selection 
					pInPlaceComboBox->SelectString(-1, strCurSelection); 
				} 
				// If combo box is not read only 
				// Create and show the in place edit control 
				else if (!IsReadOnly(iColumnIndex)) 
				{ 
					CInPlaceEdit* pInPlaceEdit = ShowInPlaceEdit(iRowIndex, iColumnIndex, strCurSelection); 
				} 
			} 
		} 
	}   
} 
 
bool CComboListCtrl::HitTestEx(CPoint &obPoint, int* pRowIndex, int* pColumnIndex) const 
{ 
	if (!pRowIndex || !pColumnIndex) 
	{ 
		return false; 
	} 
 
	// Get the row index 
	*pRowIndex = HitTest(obPoint, NULL); 
 
	if (pColumnIndex) 
	{ 
		*pColumnIndex = 0; 
	} 
 
	// Make sure that the ListView is in LVS_REPORT 
	if ((GetWindowLong(m_hWnd, GWL_STYLE) & LVS_TYPEMASK) != LVS_REPORT) 
	{ 
		return false; 
	} 
 
	// Get the number of columns 
	CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0); 
 
	int iColumnCount = pHeader->GetItemCount(); 
 
	// Get bounding rect of item and check whether obPoint falls in it. 
	CRect obCellRect; 
	GetItemRect(*pRowIndex, &obCellRect, LVIR_BOUNDS); 
 
	if (obCellRect.PtInRect(obPoint)) 
	{ 
		// Now find the column 
		for (*pColumnIndex = 0; *pColumnIndex < iColumnCount; (*pColumnIndex)++) 
		{ 
			int iColWidth = GetColumnWidth(*pColumnIndex); 
 
			if (obPoint.x >= obCellRect.left && obPoint.x <= (obCellRect.left + iColWidth)) 
			{ 
				return true; 
			} 
			obCellRect.left += iColWidth; 
		} 
	} 
	return false; 
} 
 
void CComboListCtrl::SetComboColumns(int iColumnIndex, bool bSet /*= true*/) 
{ 
	// If the Column Index is not present && Set flag is false 
	// Then do nothing  
	// If the Column Index is present && Set flag is true 
	// Then do nothing 
	POSITION Pos = m_ComboSupportColumnsList.Find(iColumnIndex); 
 
	// If the Column Index is not present && Set flag is true 
	// Then Add to list 
	if ((NULL == Pos) && bSet)  
	{ 
		m_ComboSupportColumnsList.AddTail(iColumnIndex);  
	} 
 
	// If the Column Index is present && Set flag is false 
	// Then Remove from list 
	if ((NULL != Pos) && !bSet)  
	{ 
		m_ComboSupportColumnsList.RemoveAt(Pos);  
	} 
} 
 
void CComboListCtrl::SetReadOnlyColumns(int iColumnIndex, bool bSet /*= true*/) 
{ 
	// If the Column Index is not present && Set flag is false 
	// Then do nothing  
	// If the Column Index is present && Set flag is true 
	// Then do nothing 
	POSITION Pos = m_ReadOnlyColumnsList.Find(iColumnIndex); 
 
	// If the Column Index is not present && Set flag is true 
	// Then Add to list 
	if ((NULL == Pos) && bSet)  
	{ 
		m_ReadOnlyColumnsList.AddTail(iColumnIndex);  
	} 
 
	// If the Column Index is present && Set flag is false 
	// Then Remove from list 
	if ((NULL != Pos) && !bSet)  
	{ 
		m_ReadOnlyColumnsList.RemoveAt(Pos);  
	} 
} 
 
bool CComboListCtrl::IsReadOnly(int iColumnIndex) 
{ 
	if (m_ReadOnlyColumnsList.Find(iColumnIndex)) 
	{ 
		return true; 
	} 
 
	return false; 
} 
 
bool CComboListCtrl::IsCombo(int iColumnIndex) 
{ 
	if (m_ComboSupportColumnsList.Find(iColumnIndex)) 
	{ 
		return true; 
	} 
 
	return false; 
} 
 
void CComboListCtrl::CalculateCellRect(int iColumnIndex, int iRowIndex, CRect& robCellRect) 
{ 
	GetItemRect(iRowIndex, &robCellRect, LVIR_BOUNDS); 
 
	CRect rcClient; 
	GetClientRect(&rcClient); 
 
	if (robCellRect.right > rcClient.right)  
	{ 
		robCellRect.right = rcClient.right; 
	} 
 
	ScrollToView(iColumnIndex, robCellRect);  
} 
 
void CComboListCtrl::OnEndLabelEdit(NMHDR* pNMHDR, LRESULT* pResult)  
{ 
	LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR; 
	// TODO: Add your control notification handler code here 
 
	// Update the item text with the new text 
	SetItemText(pDispInfo->item.iItem, pDispInfo->item.iSubItem, pDispInfo->item.pszText); 
 
	GetParent()->SendMessage(WM_VALIDATE, GetDlgCtrlID(), (LPARAM)pDispInfo);  
 
	*pResult = 0; 
} 
 
void CComboListCtrl::SetValidEditCtrlCharacters(CString &rstrValidCharacters) 
{ 
	m_strValidEditCtrlChars = rstrValidCharacters; 
} 
 
void CComboListCtrl::SetColumnValidEditCtrlCharacters(CString &rstrValidCharacters,int column) 
{ 
	if(column>MAX_LISTCTRL_COLUMNS-1) 
		return; 
	if(column == -1) 
	{ 
		for(int i=0;i x1 of ctrl rect or **Should not ideally happen** 
	// If the width of the cell extends beyond x2 of ctrl rect then 
	// Scroll 
 
	CSize obScrollSize(0, 0); 
 
	if (((iOffSet + robCellRect.left) < rcClient.left) ||  
		((iOffSet + robCellRect.left) > rcClient.right)) 
	{ 
		obScrollSize.cx = iOffSet + robCellRect.left; 
	} 
	else if ((iOffSet + robCellRect.left + iColumnWidth) > rcClient.right) 
	{ 
		obScrollSize.cx = iOffSet + robCellRect.left + iColumnWidth - rcClient.right; 
	} 
 
	Scroll(obScrollSize); 
	robCellRect.left -= obScrollSize.cx; 
 
	// Set the width to the column width 
	robCellRect.left += iOffSet; 
	robCellRect.right = robCellRect.left + iColumnWidth; 
} 
 
void CComboListCtrl::OnBeginLabelEdit(NMHDR* pNMHDR, LRESULT* pResult)  
{ 
	LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR; 
	// TODO: Add your control notification handler code here 
	if (IsReadOnly(pDispInfo->item.iSubItem)) 
	{ 
		*pResult = 1; 
		return; 
	} 
 
	*pResult = 0; 
} 
 
int CComboListCtrl::InsertColumn(int nCol,LPCTSTR lpszColumnHeading,int nFormat ,int nWidth,int nSubItem) 
{ 
	m_iColumnCounts++; 
	return CListCtrl::InsertColumn( nCol, lpszColumnHeading, nFormat, nWidth, nSubItem); 
} 
 
int CComboListCtrl::GetColumnCounts() 
{ 
	return m_iColumnCounts; 
} 
 
void CComboListCtrl::DeleteAllColumn() 
{ 
	for(int i=0;i