327 lines
10 KiB
C++
327 lines
10 KiB
C++
// ==========================================================================
|
|
// 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 PARENTCOMBOBOX, class PARENTLISTBOX, class PARENTEDIT>
|
|
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<COXHistoryCombo, CListBox, COXMaskedEdit> { ... }
|
|
|
|
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 PARENTCOMBOBOX, class PARENTLISTBOX, class PARENTEDIT>
|
|
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<class PARENTCOMBOBOX, class PARENTLISTBOX, class PARENTEDIT>
|
|
COXBaseSubclassedComboBox<PARENTCOMBOBOX,PARENTLISTBOX,PARENTEDIT>::
|
|
COXBaseSubclassedComboBox() : m_bSubclassedListBoxCtrl(FALSE),
|
|
m_bSubclassedEditCtrl(FALSE)
|
|
|
|
{
|
|
#ifdef _DEBUG
|
|
PARENTCOMBOBOX comboBox;
|
|
if(!comboBox.IsKindOf(RUNTIME_CLASS(CComboBox)))
|
|
{
|
|
TRACE(_T("COXBaseSubclassedComboBox<PARENTCOMBOBOX,PARENTLISTBOX,PARENTEDIT>::COXBaseSubclassedComboBox: Parent class must be CComboBox derived\n"));
|
|
AfxThrowNotSupportedException();
|
|
}
|
|
|
|
PARENTLISTBOX listBox;
|
|
if(!listBox.IsKindOf(RUNTIME_CLASS(CListBox)))
|
|
{
|
|
TRACE(_T("COXBaseSubclassedComboBox<PARENTCOMBOBOX,PARENTLISTBOX,PARENTEDIT>::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<PARENTCOMBOBOX,PARENTLISTBOX,PARENTEDIT>::COXBaseSubclassedComboBox: Parent class for the combo box edit control must be CEdit derived\n"));
|
|
AfxThrowNotSupportedException();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
template<class PARENTCOMBOBOX, class PARENTLISTBOX, class PARENTEDIT>
|
|
COXBaseSubclassedComboBox<PARENTCOMBOBOX,PARENTLISTBOX,PARENTEDIT>::
|
|
~COXBaseSubclassedComboBox()
|
|
{
|
|
}
|
|
|
|
|
|
template<class PARENTCOMBOBOX, class PARENTLISTBOX, class PARENTEDIT>
|
|
LRESULT COXBaseSubclassedComboBox<PARENTCOMBOBOX,PARENTLISTBOX,PARENTEDIT>::
|
|
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<class PARENTCOMBOBOX, class PARENTLISTBOX, class PARENTEDIT>
|
|
void COXBaseSubclassedComboBox<PARENTCOMBOBOX,PARENTLISTBOX,PARENTEDIT>::
|
|
SubclassEditCtrl(CWnd* pWnd)
|
|
{
|
|
ASSERT(pWnd!=NULL);
|
|
HWND hWnd=pWnd->GetSafeHwnd();
|
|
VERIFY(GetEditCtrl()->SubclassWindow(hWnd));
|
|
}
|
|
|
|
|
|
template<class PARENTCOMBOBOX, class PARENTLISTBOX, class PARENTEDIT>
|
|
void COXBaseSubclassedComboBox<PARENTCOMBOBOX,PARENTLISTBOX,PARENTEDIT>::
|
|
SubclassListBoxCtrl(CWnd* pWnd)
|
|
{
|
|
ASSERT(pWnd!=NULL);
|
|
HWND hWnd=pWnd->GetSafeHwnd();
|
|
VERIFY(GetListBoxCtrl()->SubclassWindow(hWnd));
|
|
}
|
|
|
|
|
|
template<class PARENTCOMBOBOX, class PARENTLISTBOX, class PARENTEDIT>
|
|
BOOL COXBaseSubclassedComboBox<PARENTCOMBOBOX,PARENTLISTBOX,PARENTEDIT>::
|
|
InitializeComboBox()
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
template<class PARENTCOMBOBOX, class PARENTLISTBOX, class PARENTEDIT>
|
|
void COXBaseSubclassedComboBox<PARENTCOMBOBOX,PARENTLISTBOX,PARENTEDIT>::
|
|
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__
|