// ========================================================================== // Class Specification : // COXBaseSubclassedComboBox // ========================================================================== // Header file : OXBaseSubclassedComboBox.h // Version: 9.3 // This software along with its related components, documentation and files ("The Libraries") // is © 1994-2007 The Code Project (1612916 Ontario Limited) and use of The Libraries is // governed by a software license agreement ("Agreement"). Copies of the Agreement are // available at The Code Project (www.codeproject.com), as part of the package you downloaded // to obtain this file, or directly from our office. For a copy of the license governing // this software, you may contact us at legalaffairs@codeproject.com, or by calling 416-849-8900. // ////////////////////////////////////////////////////////////////////////// /* OVERVIEW Most common controls are relatively easy to customize through subclassing. E.g if you need to use your own list box control with extended functionality you just have to subclass the existing list box. Most common controls are self sufficient. That means that all control's functionality resides within the control and it doesn't depend on anything else. But it is not the case with combo box control which consists of 3 controls: combo box, dropdown list box and edit (edit control is not used when LBS_DROPDOWNLIST style is specified). Imagine that you want to combine the functionality of different derived classes with extended functionality into new control. E.g you might want to create history combo box with masked edit control used to type in the items or multicolumn combo box that allows a user to type in only currency info. In this case the following template class will come in handy: template class COXBaseSubclassedComboBox : public PARENTCOMBOBOX { ... } As you can see you must provide name of the class for combo box, list box and edit control. So if you might declare new class as: class CHistoryMaskedComboBox : public COXBaseSubclassedComboBox { ... } in order to create a history combo box with masked edit control used to type in the items. Usually the declaring of new class in this way is all you have to do in order to get new functionality. But sometimes you have to provide additional initialization steps. In this case you might be interested in overriding the following virtual functions: virtual CEdit* GetEditCtrl(); virtual CListBox* GetListBoxCtrl(); virtual void SubclassEditCtrl(CWnd* pWnd); virtual void SubclassListBoxCtrl(CWnd* pWnd); Refer to the documentation on this functions for details. Dependency: #include "OXBaseSubclassedComboBox.h" */ #ifndef _OX_SUBCLASSEDCOMBOBOX_H__ #define _OX_SUBCLASSEDCOMBOBOX_H__ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 #include "OXDllExt.h" #ifdef SubclassWindow #undef SubclassWindow #endif template class COXBaseSubclassedComboBox : public PARENTCOMBOBOX { // Construction public: // --- In : // --- Out : // --- Returns: // --- Effect: Constructs the object COXBaseSubclassedComboBox(); // Attributes public: protected: // dropdown list box control PARENTLISTBOX m_listBox; // edit control PARENTEDIT m_edit; // flag that spesifies if corresponding controls has already been subclassed BOOL m_bSubclassedListBoxCtrl; BOOL m_bSubclassedEditCtrl; // Operations public: // --- In : // --- Out : // --- Returns: Pointer to the internal edit control // --- Effect: Retrieves a pointer to the internal edit control. Advanced // overridable can be overridden in order to supply non default // edit control. virtual CEdit* GetEditCtrl() { return (CEdit*)&m_edit; } // --- In : // --- Out : // --- Returns: Pointer to the internal list box control // --- Effect: Retrieves a pointer to the internal list box control. Advanced // overridable can be overridden in order to supply non default // list box control. virtual CListBox* GetListBoxCtrl() { return (CListBox*)&m_listBox; } // Implementation public: // --- In : // --- Out : // --- Returns: // --- Effect: Destructs the object virtual ~COXBaseSubclassedComboBox(); // called when the control is being subclassed virtual void PreSubclassWindow(); protected: // --- In : pWnd - pointer to a CWnd object that represents the // internal edit control. Advanced overridable, can be // overridden in order to provide additional // initialization when the object has just been // subclassed. // --- Out : // --- Returns: // --- Effect: Subclasses the internal edit control using object returned by // GetEditCtrl() function virtual void SubclassEditCtrl(CWnd* pWnd); // --- In : // --- Out : // --- Returns: TRUE if Edit control has already been subclassed // --- Effect: Retrieves the flag that specifies that edit control has already // been subclassed virtual BOOL IsSubclassedEditCtrl() const { return m_bSubclassedEditCtrl; } // --- In : pWnd - pointer to a CWnd object that represents the // internal list box control. Advanced overridable, // can be overridden in order to provide additional // initialization when the object has just been // subclassed. // --- Out : // --- Returns: // --- Effect: Subclasses the internal list box control using object returned by // GetListBoxCtrl() function virtual void SubclassListBoxCtrl(CWnd* pWnd); // --- In : // --- Out : // --- Returns: TRUE if list box control has already been subclassed // --- Effect: Retrieves the flag that specifies that list box control has // already been subclassed virtual BOOL IsSubclassedListBoxCtrl() const { return m_bSubclassedListBoxCtrl; } // --- In : // --- Out : // --- Returns: TRUE if combo box was successfully initialized // --- Effect: Initializes the internal state of the combo box. Called right // after the control was created or subclassed virtual BOOL InitializeComboBox(); // handles some messages that are important for internal implementation virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); }; ///////////////////////////////////////////////////////////////////// template COXBaseSubclassedComboBox:: COXBaseSubclassedComboBox() : m_bSubclassedListBoxCtrl(FALSE), m_bSubclassedEditCtrl(FALSE) { #ifdef _DEBUG PARENTCOMBOBOX comboBox; if(!comboBox.IsKindOf(RUNTIME_CLASS(CComboBox))) { TRACE(_T("COXBaseSubclassedComboBox::COXBaseSubclassedComboBox: Parent class must be CComboBox derived\n")); AfxThrowNotSupportedException(); } PARENTLISTBOX listBox; if(!listBox.IsKindOf(RUNTIME_CLASS(CListBox))) { TRACE(_T("COXBaseSubclassedComboBox::COXBaseSubclassedComboBox: Parent class for the dropdown list box must be CListBox derived\n")); AfxThrowNotSupportedException(); } PARENTEDIT edit; if(!edit.IsKindOf(RUNTIME_CLASS(CEdit))) { TRACE(_T("COXBaseSubclassedComboBox::COXBaseSubclassedComboBox: Parent class for the combo box edit control must be CEdit derived\n")); AfxThrowNotSupportedException(); } #endif } template COXBaseSubclassedComboBox:: ~COXBaseSubclassedComboBox() { } template LRESULT COXBaseSubclassedComboBox:: WindowProc(UINT message, WPARAM wParam, LPARAM lParam) { #if defined (_WINDLL) #if defined (_AFXDLL) AFX_MANAGE_STATE(AfxGetAppModuleState()); #else AFX_MANAGE_STATE(AfxGetStaticModuleState()); #endif #endif switch(message) { case WM_CTLCOLOREDIT: { LRESULT lResult=PARENTCOMBOBOX::WindowProc(message,wParam,lParam); if(!IsSubclassedEditCtrl()) { m_bSubclassedEditCtrl=TRUE; SubclassEditCtrl(CWnd::FromHandle((HWND)lParam)); } return lResult; } case WM_CTLCOLORLISTBOX: { LRESULT lResult=PARENTCOMBOBOX::WindowProc(message,wParam,lParam); if(!IsSubclassedListBoxCtrl()) { m_bSubclassedListBoxCtrl=TRUE; SubclassListBoxCtrl(CWnd::FromHandle((HWND)lParam)); } return lResult; } case WM_CREATE: { LRESULT lResult=PARENTCOMBOBOX::WindowProc(message,wParam,lParam); if(!InitializeComboBox()) { lResult=FALSE; } return lResult; } } return PARENTCOMBOBOX::WindowProc(message,wParam,lParam); } template void COXBaseSubclassedComboBox:: SubclassEditCtrl(CWnd* pWnd) { ASSERT(pWnd!=NULL); HWND hWnd=pWnd->GetSafeHwnd(); VERIFY(GetEditCtrl()->SubclassWindow(hWnd)); } template void COXBaseSubclassedComboBox:: SubclassListBoxCtrl(CWnd* pWnd) { ASSERT(pWnd!=NULL); HWND hWnd=pWnd->GetSafeHwnd(); VERIFY(GetListBoxCtrl()->SubclassWindow(hWnd)); } template BOOL COXBaseSubclassedComboBox:: InitializeComboBox() { return TRUE; } template void COXBaseSubclassedComboBox:: PreSubclassWindow() { _AFX_THREAD_STATE* pThreadState=AfxGetThreadState(); // hook not already in progress if(pThreadState->m_pWndInit==NULL) { if(!InitializeComboBox()) { TRACE(_T("COXBaseSubclassedComboBox::PreSubclassWindow: failed to initialize the control\n")); } } PARENTCOMBOBOX::PreSubclassWindow(); } ///////////////////////////////////////////////////////////////////// #endif // #ifndef _OX_SUBCLASSEDCOMBOBOX_H__