4

私のメインクラスに、CTreeViewコントロールから派生したクラスであるプライベートメンバーがあるとしましょう。メインクラス自体でこのツリービューコントロールからのメッセージを処理するにはどうすればよいですか?

これは、Visual Studiosが構築するMDIベースアプリケーションに似ています。ここでは、CClassViewおよびCFileViewという名前の2つのドッキング可能なツリービューコントロールがあり、それぞれに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;
}

2回目の試行:

//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はすでに親に送信されています。ただし、MFCのメッセージリフレクションは、ON_NOTIFY_REFLECTが子に存在する場合、通知を子ウィンドウのメッセージマップにルーティングします。

親にメッセージ処理でも発言権を持たせたい場合は、ON_NOTIFY_REFLECTをON_NOTIFY_REFLECT_EXに変更し、反映されたメッセージハンドラーでFALSEを返すことができます。

親でWM_NOTIFYを取得するため、通知を処理する方法は、ダイアログのツリーコントロールで通常行うように、ツリービューの親にON_NOTIFYマクロを追加することです。ビューのIDは、指定していない場合はAFX_IDW_PANE_FIRSTである可能性があります。

于 2012-11-21T20:43:45.233 に答える
3

シェンは私の問題を理解することができましたが、今振り返ると非常に些細なことでした。多分これは同じ質問をするかもしれない他の人を助けるでしょう。

Visual Studio2010から生成したVisualStudioスタイルプログラムを使用した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

説明されているケースでは、コントロールCViewTreeから親CFileViewにWM_NOTIFY TVN_SELCHANGEDメッセージで通知する場合は、メッセージマップを使用せずに、仮想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 に答える