4

假设我的主类有一个私有成员,它是从 CTreeView 控件派生的类。如何处理来自主类本身的树视图控件的消息?

这类似于 Visual Studios 为您构建的 MDI 基础应用程序,其中您有两个名为 CClassView 和 CFileView 的可停靠树视图控件,并且每个都有一个从 CTreeView 派生的私有成员。

我可以像这样将来自子成员控件 CViewTree 的消息传递给我的 CFileView 类吗?

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

此代码引发异常,但如果这确实有效,我将如何处理父类中的 TVN_SELCHANGED 消息?

编辑:所以我尝试了以下建议,但其中任何一个都没有太多运气。

//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;
}

第二次尝试:

//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");
}
4

3 回答 3

7

不确定为什么要这样做,因为视图和父级之间存在紧密耦合,因此代码可重用性较低。如果您想重用选择逻辑,您可以像DRAWCLI 示例那样将其提取到一个单独的类中。

TVN_SELCHANGED 已发送给父级。但是,当子窗口中存在 ON_NOTIFY_REFLECT 时,MFC 的消息反射将通知路由到子窗口的消息映射。

如果您希望父级在消息处理中也有发言权,您可以将 ON_NOTIFY_REFLECT 更改为 ON_NOTIFY_REFLECT_EX 并在反射消息处理程序中返回 FALSE。

您将在父级处获得 WM_NOTIFY,因此您处理通知的方式是将ON_NOTIFY 宏添加到树形视图的父级,就像您通常对对话框上的树形控件所做的那样。如果您没有指定视图的 ID,则该视图的 ID 可能是 AFX_IDW_PANE_FIRST。

于 2012-11-21T20:43:45.233 回答
3

盛能够找出我的问题,现在回想起来是很微不足道的。也许这会帮助其他可能有同样问题的人。

在我从 Visual Studio 2010 生成的带有 Visual Studio 风格的 MDI 程序中,CFileView 有一个 CViewTree 的子成员实例。CViewTree 是从 CTreeCtrl 派生的。

默认情况下,MFC 已经将消息沿子到父链传递。答案是确定控件 ID 以从您的父类中获取通知消息。

所以,首先,我们需要知道树控件的 ID。在CFileView的OnCreate方法中,可以看到这段代码:

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

MSDN 对 Create 方法有以下内容:

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

在我的示例中,id 为 4。现在在父级(在本例中为 CFileView)中,只需创建您的 ON_NOTIFY 宏:

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

我必须手动输入上面的行,因为父类的类向导或消息属性没有 =TVN_SELCHANGED 消息。接下来,确保您的处理程序方法 OnSelChanged 在 CFileView.h 文件中声明为:

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

现在我可以像这样处理 TVN_SELCHANGED 消息(回到 CFileView.cpp 中):

void CFileView::OnSelChanged(NMHDR *pNMHDR, LRESULT *pResult)
{
    HTREEITEM item = m_wndFileView.GetSelectedItem();
    AfxMessageBox(m_wndFileView.GetItemText(item));
}
于 2012-11-26T18:13:10.937 回答
0

在所描述的情况下,如果您想使用 WM_NOTIFY TVN_SELCHANGED 消息从控件 CViewTree 通知父 CFileView,您应该在虚拟 OnNotify 函数中执行此操作,而不是使用消息映射。如果 OnNotify 没有遇到正确的处理程序,消息将转到父​​ CMainFrame,您可以在那里使用消息映射。

BOOL CFileView::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
   if (nmHdr->idFrom != 4)
      return CDockablePane::OnNotify(wParam, lParam, pResult);
   if (nmHdr->code == TVN_SELCHANGED)
   {
      OnItemsSelChanged((NMHDR*)lParam, pResult);
      return TRUE;
   }
   return FALSE;
}
于 2016-03-22T13:15:38.977 回答