Wednesday, December 5, 2007

How to subclass CListBox and CEdit inside of CComboBox

SUMMARY

While it is simple to directly subclass a combo box control, it is not simple to subclass the edit or list box inside a combo box. The problem is that it is difficult to get the HWNDs of the child controls in a portable manner.

One safe way to subclass the internal edit and list box controls is to subclass them in the WM_CTLCOLORXXX messages. Because Win32 sends separate WM_CTLCOLOREDIT and WM_CTLCOLORLISTBOX messages, these messages are safe and easy ways to get the HWNDs of the child controls of the combo box.

Below is a CSuperComboBox class, which is an MFC implementation of this method. Because MFC routes all the WM_CTLCOLOR messages to OnCtlColor, the subclassing takes place there.

MORE INFORMATION

Use ClassWizard to derive a class from CComboBox and add message handlers for WM_CTLCOLOR and WM_DESTROY. Then manually edit the header file to add the data members, m_edit and m_listbox. Finally, copy the code from the message handlers below:

Sample code:

// SuperComboBox.h : header file

class CSuperComboBox : public CComboBox

{

public:

CEdit m_edit;

CListBox m_listbox;

protected:

afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);

afx_msg void OnDestroy();

...

};

// SuperComboBox.cpp : implementation file

HBRUSH CSuperComboBox::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)

{

if (nCtlColor == CTLCOLOR_EDIT)

{

// Edit control

if (m_edit.GetSafeHwnd() == NULL)

m_edit.SubclassWindow(pWnd->GetSafeHwnd());

}

else if (nCtlColor == CTLCOLOR_LISTBOX)

{

//ListBox control

if (m_listbox.GetSafeHwnd() == NULL)

m_listbox.SubclassWindow(pWnd->GetSafeHwnd());

}

HBRUSH hbr = CComboBox::OnCtlColor(pDC, pWnd, nCtlColor);

return hbr;

}

void CSuperComboBox::OnDestroy()

{

if (m_edit.GetSafeHwnd() != NULL)

m_edit.UnsubclassWindow();

if (m_listbox.GetSafeHwnd() != NULL)

m_listbox.UnsubclassWindow();

CComboBox::OnDestroy();

}

No comments: