Click here to Skip to main content
15,896,434 members
Articles / Desktop Programming / MFC

VCOMBOBX in MFC - A Virtual Combo Box Control

Rate me:
Please Sign up or sign in to vote.
4.91/5 (33 votes)
4 Jan 2011CPOL8 min read 72.1K   11.3K   108  
A MFC based virtual combo box
/* 
 * Kenny Liu
 * http://www.codeproject.com/Members/yonken
 *
 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
 * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
 *
 * Permission is hereby granted to use or copy this program
 * for any purpose,  provided the above notices are retained on all copies.
 * Permission to modify the code and to distribute modified code is granted,
 * provided the above notices are retained, and a notice that the code was
 * modified is included with the above copyright notice.
 */

#ifndef __OBJINFOCONTROL_H__
#define __OBJINFOCONTROL_H__


#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "ObjInfoHolder.h"
#include "CustomDrawControl.h"
#include "VComboBox.h"

/*----------------------------------------------------------------------------*/
/* Global control
/*----------------------------------------------------------------------------*/

#define RETRIEVE_OBJINFO_IN_NEWTHREAD	// Create a separate thread to do the job

#define UPDATE_OBJINFO_VIA_TIMER		// Update the content of the list via the timer

#ifdef UPDATE_OBJINFO_VIA_TIMER
	#define UPDATE_INFOLIST_TIMER_ID		1
	#define UPDATE_INFOLIST_TIMER_ELAPSE	600
#endif // UPDATE_OBJINFO_VIA_TIMER

#define DERIVE_FROM_VCOMBO				// To switch the base class of CObjInfoComboBox and CObjInfoListBox

#pragma warning(push, 2)
#pragma warning(disable: 4786)

#include <map>	// For mapping the file extensions and the related image index inside CImageList
typedef std::map<tstring, int>	FileIconMap;

#pragma warning(pop)

/*----------------------------------------------------------------------------*/
/* IIconMapper
/*----------------------------------------------------------------------------*/
class IIconMapper : public ILockableObj
{
public:
	IIconMapper(int cx = 16, int cy = 16);
	virtual ~IIconMapper();
public:
	CImageList&	GetImageList()	{ return m_ImageList; }

	// return -1 means not found
	virtual int GetIconIndex(CObjInfoMatcher* pMatcher, WPARAM wParam, LPARAM lParam = 0) = 0;
protected:
	CImageList	m_ImageList;
};

/*----------------------------------------------------------------------------*/
/* CAsciiProgressGenerator
/*----------------------------------------------------------------------------*/
class CAsciiProgressGenerator
{
public:
	CAsciiProgressGenerator(DWORD dwMinTimeLimit = 600);
public:
	CString	GetProressAscii();
protected:
	UINT	m_nProgress;
	DWORD	m_dwMinTimeLimit;
	DWORD	m_dwCurrentTime;
};


/*----------------------------------------------------------------------------*/
/* CObjInfoListCtrl
/*----------------------------------------------------------------------------*/

#define WM_OBJINFO_THREADEVENT			(WM_USER+0x400)

/*
	An implementation of virtual list-control
*/

#define WM_OBJINFOLIST_UPDATE			(WM_USER+0x500)

#ifndef CObjInfoListCtrlBase
	#define CObjInfoListCtrlBase	CCustomDrawListCtrl
#endif // CObjInfoListCtrlBase

class CObjInfoListCtrl : public CObjInfoListCtrlBase, public IObserver
{
	DECLARE_DYNCREATE(CObjInfoListCtrl)
public:
	CObjInfoListCtrl();
	virtual ~CObjInfoListCtrl();
public:
	virtual void SetObjInfoMatcher(CObjInfoMatcher* pMatcher, BOOL bSubscribeThreadEvent = TRUE);
	inline CObjInfoMatcher* GetObjInfoMatcher() const								{ return m_pObjInfoMatcher; }
	inline CMultiColInfoHolder* GetObjInfoHolder() const
	{
		return m_pObjInfoMatcher ? (CMultiColInfoHolder*)m_pObjInfoMatcher->GetObjInfoHolder() : NULL;
	}

	virtual void			SetIconMapper(IIconMapper* pIconMapper)					{ m_pIconMapper = pIconMapper; }
	virtual IIconMapper*	GetIconMapper() const									{ return m_pIconMapper; }
public:
	virtual BOOL RefreshObjInfoList();

	virtual void AutoResizeColumn();
	virtual int GetItemIconIndex(int nItem);

#ifdef UPDATE_OBJINFO_VIA_TIMER
	void		SetUpdateListByTimer(BOOL bSet = TRUE)								{ m_bUpdateListByTimer = bSet; }
	void		OnTimer(UINT nIDEvent);
#endif // UPDATE_OBJINFO_VIA_TIMER

	BOOL		LoadColumnLabels(UINT nResID);
protected:
	virtual int	GetFindObjInfoListColumnIndex() const								{ return 0; }
	virtual void OnInitList();
	virtual void OnDestroyList();

	virtual void OnUpdateObjInfoList(bool bAutoResizeColumns = true);

	virtual bool IsSortable() const;
	virtual BOOL OnSort(int nCol);
protected:
	afx_msg void OnGetObjListDispInfo(NMHDR* pNMHDR, LRESULT* pResult);
	afx_msg void OnOdFindObjListItem(NMHDR* pNMHDR, LRESULT* pResult);
	afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);

#ifdef UPDATE_OBJINFO_VIA_TIMER
	BOOL			m_bUpdateListByTimer;
	UINT_PTR		m_nTimer;
#endif // UPDATE_OBJINFO_VIA_TIMER

	LRESULT			OnObjInfoThreadEvent(WPARAM wParam, LPARAM lParam);
	virtual void	OnNotify(ISubject* pSubject, WPARAM wParam = 0, LPARAM lParam = 0);
protected:
	CObjInfoMatcher*	m_pObjInfoMatcher;
	CStringArray		m_arrColumnLabels;
	IIconMapper*		m_pIconMapper;
protected:
	DECLARE_MESSAGE_MAP()
};

/*----------------------------------------------------------------------------*/
/* CFileIconMapper
/*----------------------------------------------------------------------------*/
class CFileIconMapper : public IIconMapper
{
public:
	CFileIconMapper(int cx = 16, int cy = 16);
	virtual ~CFileIconMapper();
public:
	int GetFileIconIndex(const CFileInfoEnumerator::FileInfo* pFileInfo);
	int GetFileIconIndex(LPCTSTR lpcszFilePath, LPCTSTR lpcszFileExt);
	int GetFileIconIndex(LPCTSTR lpcszFilePath);
protected:
	virtual int GetIconIndex(CObjInfoMatcher* pMatcher, WPARAM wParam, LPARAM lParam = 0);
protected:
	FileIconMap		m_FileIconIndexMap;
};

/*----------------------------------------------------------------------------*/
/* CFileInfoListCtrl
/*----------------------------------------------------------------------------*/

#ifndef CFileInfoListCtrlBase
	#define CFileInfoListCtrlBase	CObjInfoListCtrl
#endif // CFileInfoListCtrlBase

class CFileInfoListCtrl : public CFileInfoListCtrlBase
{
	DECLARE_DYNCREATE(CFileInfoListCtrl)
public:
	CFileInfoListCtrl();
	virtual ~CFileInfoListCtrl();
public:
	virtual IIconMapper*	GetIconMapper() const;
protected:
	LRESULT				OnObjInfoThreadEvent(WPARAM wParam, LPARAM lParam);
protected:
	DECLARE_MESSAGE_MAP()
};

/*----------------------------------------------------------------------------*/
/* CObjInfoListBox
/*----------------------------------------------------------------------------*/

#ifndef CObjInfoListBoxBase
	#ifdef DERIVE_FROM_VCOMBO
		#define CObjInfoListBoxBase	CVComboListBox
	#else
		#define CObjInfoListBoxBase	CComboListBox
	#endif // DERIVE_FROM_VCOMBO
#endif // CObjInfoListBoxBase

class CObjInfoListBox : public CObjInfoListBoxBase, public IObserver
{
	DECLARE_DYNCREATE(CObjInfoListBox)
public:
	CObjInfoListBox();
	virtual ~CObjInfoListBox();
public:
	virtual BOOL Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID);
	virtual BOOL CreateFromCtrl(CWnd* pParent, int nID, DWORD dwStyleAdd = 0);
public:
	virtual CString GetItemText(UINT nItem);

	virtual void SetObjInfoMatcher(CObjInfoMatcher* pMatcher, BOOL bSubscribeThreadEvent = TRUE);
	
	inline CObjInfoMatcher* GetObjInfoMatcher() const							{ return m_pObjInfoMatcher; }
	
	inline CMultiColInfoHolder* GetObjInfoHolder() const
	{
		return m_pObjInfoMatcher ? (CMultiColInfoHolder*)m_pObjInfoMatcher->GetObjInfoHolder() : NULL;
	}

	virtual void			SetIconMapper(IIconMapper* pIconMapper)				{ m_pIconMapper = pIconMapper; }
	virtual IIconMapper*	GetIconMapper() const								{ return m_pIconMapper; }

	virtual int			GetItemIconIndex(UINT nItem);

	virtual WPARAM		GetObjInfoTextInMatchWPARAM(UINT nItem)					{ return nItem; }
	virtual LPARAM		GetObjInfoTextInMatchLPARAM(UINT nItem)					{ return 0; }

#ifdef UPDATE_OBJINFO_VIA_TIMER
	void				SetUpdateListByTimer(BOOL bSet = TRUE)					{ m_bUpdateListByTimer = bSet; }
	void				OnTimer(UINT nIDEvent);
#endif // UPDATE_OBJINFO_VIA_TIMER

	virtual void	AutoFitContentHScroll();

	virtual BOOL	RefreshObjInfoList();
protected:
	virtual void	OnInitListBox();
	virtual void	OnDestroyListBox();
	void			OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
protected:
	LRESULT			OnObjInfoThreadEvent(WPARAM wParam, LPARAM lParam);
	virtual void	OnNotify(ISubject* pSubject, WPARAM wParam = 0, LPARAM lParam = 0);

	virtual void	OnUpdateObjInfoList();
protected:
#ifdef UPDATE_OBJINFO_VIA_TIMER
	BOOL				m_bUpdateListByTimer;
	UINT_PTR			m_nTimer;
#endif // UPDATE_OBJINFO_VIA_TIMER
	CFont				m_font;
	CObjInfoMatcher*	m_pObjInfoMatcher;
	IIconMapper*		m_pIconMapper;
protected:
	DECLARE_MESSAGE_MAP()
};

/*----------------------------------------------------------------------------*/
/* CFileInfoListBox
/*----------------------------------------------------------------------------*/

#ifndef CFileInfoListBoxBase
	#define CFileInfoListBoxBase	CObjInfoListBox
#endif // CFileInfoListBoxBase

class CFileInfoListBox : public CFileInfoListBoxBase
{
	DECLARE_DYNCREATE(CFileInfoListBox)
public:
	CFileInfoListBox();
	virtual ~CFileInfoListBox();
public:
	virtual IIconMapper*	GetIconMapper() const;
protected:
	virtual LPARAM		GetObjInfoTextInMatchLPARAM(UINT nItem)		{ return CFileInfoEnumerator::FIT_FILEPATH; }
	LRESULT				OnObjInfoThreadEvent(WPARAM wParam, LPARAM lParam);
protected:
	DECLARE_MESSAGE_MAP()
};

/*----------------------------------------------------------------------------*/
/* CObjInfoComboBox
/*----------------------------------------------------------------------------*/

#ifndef CObjInfoComboBoxBase
	#ifdef DERIVE_FROM_VCOMBO
		#define CObjInfoComboBoxBase	CVComboBox
	#else
		#define CObjInfoComboBoxBase	CCustomDrawComboBox
	#endif // DERIVE_FROM_VCOMBO
#endif // CObjInfoComboBoxBase

class CObjInfoComboBox : public CObjInfoComboBoxBase, public IObserver
{
	DECLARE_DYNCREATE(CObjInfoComboBox)
public:
	CObjInfoComboBox();
	virtual ~CObjInfoComboBox();
public:
	virtual BOOL Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID);

	virtual void SetObjInfoMatcher(CObjInfoMatcher* pMatcher, BOOL bSubscribeThreadEvent = TRUE);

	inline CObjInfoMatcher* GetObjInfoMatcher() const							{ return m_pObjInfoMatcher; }

	inline CMultiColInfoHolder* GetObjInfoHolder() const
	{
		return m_pObjInfoMatcher ? (CMultiColInfoHolder*)m_pObjInfoMatcher->GetObjInfoHolder() : NULL;
	}

	virtual void			SetIconMapper(IIconMapper* pIconMapper);
	virtual IIconMapper*	GetIconMapper() const								{ return m_pIconMapper; }

	virtual int				GetItemIconIndex(UINT nItem);

	virtual CComboListBox& GetComboListBox()
	{
		if ( GetObjInfoListBox() )
			return *GetObjInfoListBox();
		return CObjInfoComboBoxBase::GetComboListBox();
	}

	virtual CObjInfoListBox* GetObjInfoListBox()								{ return NULL; }

	virtual CString GetItemText(UINT nItem);

	virtual size_t	GetMatchItemCount(LPCTSTR lpcszPattern, PINT pSelItem = NULL);
	
	virtual WPARAM	GetObjInfoTextInMatchWPARAM(UINT nItem)						{ return nItem; }
	virtual LPARAM	GetObjInfoTextInMatchLPARAM(UINT nItem)						{ return 0; }

	BOOL			IsAutoCompleteEnabled() const								{ return m_bAutoComplete; }
	void			EnableAutoComplete(BOOL bEnable = TRUE)						{ m_bAutoComplete = bEnable; }

	virtual BOOL	RefreshObjInfoList();

#ifdef UPDATE_OBJINFO_VIA_TIMER
	void			SetUpdateListByTimer(BOOL bSet = TRUE)						{ m_bUpdateListByTimer = bSet; }
	void			OnTimer(UINT nIDEvent);
#endif // UPDATE_OBJINFO_VIA_TIMER
protected:
	virtual void	OnUpdateObjInfoList();
	LRESULT			OnObjInfoThreadEvent(WPARAM wParam, LPARAM lParam);
	virtual void	OnNotify(ISubject* pSubject, WPARAM wParam = 0, LPARAM lParam = 0);
	virtual BOOL	OnInitCombo();
	virtual void	OnDestroyCombo();

	void			OnEditDispChange();
protected:
	// For auto complete
	void		OnDropDown();
	LRESULT		OnSetCurSel(WPARAM nIndex, LPARAM);
	void		OnKeyDown( UINT nChar, UINT nRepCnt, UINT nFlags );

#ifndef DERIVE_FROM_VCOMBO
	void		OnEditUpdate();
#endif // DERIVE_FROM_VCOMBO
	
	void		OnSelChange();
	void		OnSelEndOK();
protected:
	CObjInfoMatcher*	m_pObjInfoMatcher;
	IIconMapper*		m_pIconMapper;
	BOOL				m_bAutoComplete;
	BOOL				m_bFilterListOnDropDown;

#ifdef UPDATE_OBJINFO_VIA_TIMER
	BOOL				m_bUpdateListByTimer;
	UINT_PTR			m_nTimer;
#endif // UPDATE_OBJINFO_VIA_TIMER
protected:
	DECLARE_MESSAGE_MAP()
};

/*----------------------------------------------------------------------------*/
/* CFileInfoComboBox
/*----------------------------------------------------------------------------*/

#ifndef CFileInfoComboBoxBase
	#define CFileInfoComboBoxBase	CObjInfoComboBox
#endif // CFileInfoComboBoxBase

class CFileInfoComboBox : public CFileInfoComboBoxBase
{
	DECLARE_DYNCREATE(CFileInfoComboBox)
public:
	CFileInfoComboBox();
	virtual ~CFileInfoComboBox();
public:
	virtual IIconMapper*		GetIconMapper() const;

	virtual CFileInfoListBox&	GetFileInfoListBox()									{ return m_FileInfoListBox; }
protected:
	virtual LPARAM				GetObjInfoTextInMatchLPARAM(UINT nItem)					{ return CFileInfoEnumerator::FIT_FILEPATH; }
	LRESULT						OnObjInfoThreadEvent(WPARAM wParam, LPARAM lParam);

	virtual CObjInfoListBox*	GetObjInfoListBox();
protected:
	CFileInfoListBox	m_FileInfoListBox;
protected:
	DECLARE_MESSAGE_MAP()
};

/*----------------------------------------------------------------------------*/
/* IObjInfoController
/*----------------------------------------------------------------------------*/
class IObjInfoController
{
public:
	virtual CWnd&				GetControl()		= 0;
	virtual CObjInfoHolder&		GetInfoHolder()		= 0;
	virtual CObjInfoMatcher&	GetMatcher()		= 0;
};

template <typename TCtrl, typename TInfoHolder, typename TMatcher>
class CObjInfoController : public IObjInfoController
{
public:
	CObjInfoController(BOOL bSubscribeThreadEvent = TRUE)
	{
		Matcher().SetObjInfoHolder( &InfoHolder() );
		Control().SetObjInfoMatcher( &Matcher(), bSubscribeThreadEvent );
	}
public:
	TCtrl&				Control()			{ return m_ctrl; }
	TInfoHolder&		InfoHolder()		{ return m_infoHolder; }
	TMatcher&			Matcher()			{ return m_matcher; }
protected:
	CWnd&				GetControl()		{ return m_ctrl; }
	CObjInfoHolder&		GetInfoHolder()		{ return m_infoHolder; }
	CObjInfoMatcher&	GetMatcher()		{ return m_matcher; }
protected:
	TCtrl			m_ctrl;
	TInfoHolder		m_infoHolder;
	TMatcher		m_matcher;
};

#else
	#error ### repeated include of ObjInfoControl.h!!!
#endif // __OBJINFOCONTROL_H__

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 Code Project Open License (CPOL)


Written By
Software Developer
China China
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions