2012-11-21 33 views
4

假設我的主類有一個私有成員,它是從CTreeView控件派生的類。我如何處理主類本身的樹視圖控件中的消息?(MFC)如果控件是私有成員,父類如何接收控件的消息?

這與Visual Studio爲您構建的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"); 
} 

回答

7

不知道爲什麼你要做到這一點,你有更少的代碼的可重用你的觀點和家長之間的緊密耦合。如果您想重新使用選擇邏輯,您可以將其解壓到單獨的類中,如DRAWCLI sample

TVN_SELCHANGED已發送給父母。但是,當子ON_NOTIFY_REFLECT存在時,MFC的message reflection將通知路由到子窗口的消息映射。

如果您希望父級在消息處理中也有發言權,那麼可以將ON_NOTIFY_REFLECT更改爲ON_NOTIFY_REFLECT_EX,並在反射的消息處理程序中返回FALSE。

您將在父級獲得WM_NOTIFY,因此處理通知的方式是將a ON_NOTIFY macro添加到樹視圖的父級,就像您通常爲對話框上的樹控件所做的那樣。如果您沒有指定,則視圖的ID可能爲AFX_IDW_PANE_FIRST。

+0

優秀的寫作。許多人試圖「烹飪」MFC已經提供的功能。 –

+0

說實話,我不想這樣做。我想要做到「正確」的方式。我嘗試過在父級處理TVN_SELCHANGED,但它不起作用。當然,這很可能是我做錯了。你能否給我一個例子,你將如何處理父母的這個信息? –

+0

您將在父級獲得WM_NOTIFY,因此您所做的是將ON_NOTIFY宏添加到樹視圖的父級,就像您通常爲對話框上的樹控制所做的一樣。如果您沒有指定,則視圖的ID可能爲AFX_IDW_PANE_FIRST。 –

2

盛能夠找出我的問題,現在回頭看起來很瑣碎。也許這會幫助其他可能有同樣問題的人。

在我從Visual Studio 2010生成的MDI w/visual studio樣式程序中,CFileView具有CViewTree的子成員實例。 CViewTree是從CTreeCtrl派生而來的。

默認情況下,MFC已經將消息傳遞給子對母鏈。答案是確定控制ID以從父類中獲取通知消息。

所以,首先,我們需要知道樹控件的ID。在CFileView的OnCreate方法,你可以看到這樣的代碼:

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

MSDN先後爲創建方法如下:

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消息。

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)); 
} 
接下來,確保你的處理方法OnSelChanged在CFileView.h文件聲明
+0

我不是個聰明人。 –

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