Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

(MFC) How can a parent class receive a control's messages if the control is a private member?

Let's say my main class has a private member that is a class derived from a CTreeView control. How can I handle the messages from this tree view control on the main class itself?

This is similar to the MDI base application that Visual Studios builds for you, where you have two dockable tree view controls named CClassView and CFileView and each has a private member that's derived from CTreeView.

Can I pass the message from the child member control CViewTree to my CFileView class with like this?

void CViewTree::OnTvnSelchanged(NMHDR *pNMHDR, LRESULT *pResult)
{
    GetParent()->SendMessage(WM_NOTIFY, 0, (LPARAM)pNMHDR);
}

This code throws an exception, but if this does work, how would I handle the TVN_SELCHANGED message in the parent class?

Edit: So I've tried the following suggestions but haven't had much luck with either one.

//First try, in the parent .h file:
afx_msg BOOL OnSelChange(NMHDR *pNMHDR, LRESULT *pResult);

//In the .cpp file:
ON_NOTIFY_REFLECT_EX(TVN_SELCHANGED, OnSelChange)

//and

BOOL ParentClass::OnSelChange(NMHDR *pNMHDR, LRESULT *pResult)
{
     AfxMessageBox(L"in handler");
     Return TRUE;
}

Second try:

//in the parent .h file:
afx_msg void OnSelChange(NMHDR *pNMHDR, LRESULT *pResult);

//In the .cpp file:
ON_NOTIFY(TVN_SELCHANGED, AFX_IDW_PANE_FIRST, OnSelChange)

//and
void  ParentClass::OnSelChange(NMHDR *pNMHDR, LRESULT *pResult)
{
     AfxMessageBox(L"in handler");
}
like image 673
subject_x Avatar asked Dec 26 '22 14:12

subject_x


2 Answers

Sheng was able to figure out my problem, which looking back now was quite trivial. Maybe this will help others who might have the same question.

In the MDI w/ visual studio style program that I generated from Visual Studio 2010, the CFileView has a child member instance of CViewTree. CViewTree was derived from CTreeCtrl.

By default, MFC is already passing the messages up the child-to-parent chain. The answer is determining the control ID to get notification messages from in your parent class.

So, first things first, we need to know the ID of the tree control. In the OnCreate method of CFileView, you can see this code:

if (!m_wndFileView.Create(dwViewStyle, rectDummy, this, 4))

MSDN has the following for the Create method:

virtual BOOL Create(
   DWORD dwStyle,
   const RECT& rect,
   CWnd* pParentWnd,
   UINT nID 
);

In my example, the id is 4. Now in the parent (CFileView in this case), just create your ON_NOTIFY macro as such:

BEGIN_MESSAGE_MAP(CFileView, CDockablePane)  //precreated for you
    ON_NOTIFY(TVN_SELCHANGED, 4, OnSelChanged)  //you create this
END_MESSAGE_MAP()  //precreated for you

I had to type the line above by hand because the class wizard or message property for the parent didn't have a =TVN_SELCHANGED message. Next, make sure your handler method OnSelChanged is declared in the CFileView.h file as:

afx_msg void OnSelChanged(NMHDR *pNMHDR, LRESULT *pResult);

Now I'm able to handle the TVN_SELCHANGED message like this (back in the CFileView.cpp):

void CFileView::OnSelChanged(NMHDR *pNMHDR, LRESULT *pResult)
{
    HTREEITEM item = m_wndFileView.GetSelectedItem();
    AfxMessageBox(m_wndFileView.GetItemText(item));
}
like image 34
subject_x Avatar answered Mar 30 '23 01:03

subject_x


Not sure why you want to do this, you have less code reusability as you have a tight coupling between the view and the parent. If you want to reuse the selection logic, you can extract it out into a separate class like the DRAWCLI sample does.

TVN_SELCHANGED is already sent to the parent. However MFC's message reflection routes the notification to the child window's message map when ON_NOTIFY_REFLECT is present in the child.

If you want the parent to have a say in the message processing as well, you can change ON_NOTIFY_REFLECT to ON_NOTIFY_REFLECT_EX and return FALSE in the reflected message handler.

You will get a WM_NOTIFY at the parent so the way you handle the notification is to add a ON_NOTIFY macro to the parent of the tree view like you normally do for a tree control on a dialog. The view's id is likely AFX_IDW_PANE_FIRST if you haven't specified one.

like image 182
Sheng Jiang 蒋晟 Avatar answered Mar 30 '23 00:03

Sheng Jiang 蒋晟