明けましておめでとうございます。
毎度お世話になります、Chikunです。
環境 Windows2000SP4 VC++6.0SP6 MFC SDI
スプリッタウィンドウからPopUpMenuを経由してDialogを呼び出した時(Dialog.DoModal)、
表示されたDialogが無反応になってしまいます。
別プロセスのWindowを1度アクティブ(クリック)にすると、正常なDialog表示になります。
Dialogの代わりMessageBox等を表示すると問題無くなります。
プロジェクト A にて MFC SDI(デフォルト設定)を作成し、CTreeViewクラス B を追加しま
す。
CSplitterWndを使用して2分割スプリッタウィンドウにします。
リソースにPopUp用Menu(PopUpMenu01)とDialog(CDlg01)を用意します。
TreeView側ペインからPopUpMenuを表示させます。
PopUpMenuからCTreeViewクラスへメッセージコマンドを送りDialogを呼び出します。
TreeView側ペインからPopUpMenuの呼び出しソース。
void CB::OnRButtonDown(UINT nFlags, CPoint point)
{
// TODO: この位置にメッセージ ハンドラ用のコードを追加するかまたはデフォルトの処
理を呼び出してください
CTreeCtrl& tree = GetTreeCtrl();
TVHITTESTINFO TVHit;
CPoint pt;
GetCursorPos(&pt);
ScreenToClient(&pt);
TVHit.pt = pt;
tree.HitTest(&TVHit);
tree.SelectItem(TVHit.hItem);
CMenu menu;
CMenu* pPopup;
CFrameWnd* pFrmWnd = (CMainFrame*)AfxGetMainWnd();
VERIFY(menu.LoadMenu(IDR_PopUpMenu01));
pPopup = menu.GetSubMenu(0);
ClientToScreen(&point);
pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON, point.x, point.y,
pFrmWnd);
CTreeView::OnRButtonDown(nFlags, point);
}
Dialogの呼び出しソース。
void CB::OnPopUpMenu01()
{
CDlg01 dlg;
dlg.DoModal();
}
何か注意点等ありましたら、よろしくご教授下さい。
OnPopUpMenu01のなかで、一時停止状態になるのがダメなのかも。
> CDlg01 dlg;
> dlg.DoModal();
の処理を別関数(ユーザメッセージかなんか)にして、PostMessageで呼び出してみてはど
うでしょうか?
Blueさん、毎度ありがとうございます。
void CB:OnPop0101()
{
this->PostMessage(WM_01);
}
LRESULT CB::On01(WPARAM wp, LPARAM lp)
{
CDlg01 dlg;
dlg.DoModal();
return(1);
}
Postしてみましたが、症状はかわりませんでした。
CDlg01のリソース設定はデフォルトですが、ストイル等の変更が必要なのでしょうか?
明示的にそのダイアログの親を指定してみてはどうでしょう?
CBを親にしていいのであれば、CDlg01 dlg(this);とすれば良いと思います。
本来はこのようにダイアログのインスタンス生成時に親を明示的に指定した方が
CDialogクラスの中で涙ぐましい努力をして親ウインドウを捜さなくて良いので
効率が良いはずです。
CDialogクラスのコンストラクタでは、リソースIDと親ウインドウのポインタになって
いますが、派生クラス側では、リソースIDは内部に定義した物を引き渡すようになって
いるので、派生側のコンストラクタでは親ウインドウのポインタのみの指定になって
いると思います。
PATIOさん、お世話になります。
void CB:OnPop0101()
{
CDlg01 dlg(this);
dlg.DoModal();
}
症状はかわりませんでした。
色々な所で this を指定して試したのですが、思うようにいきませんでした。
PopUpMenuの親ウインドウをスプリッタウィンドウにしていること自体が間違えなので
しょうか。
スプリッタウインドウを親にしているのではなくて
ペインに表示しているViewを親にしているのではないでしょうか?
スプリッタウインドウコントロールがメインフレームのViewにはまって
スプリッタウインドウコントロールのペインにTreeViewがはまって
いるのではないでしょうか。
この辺の用語は分けて考えた方が良いとおもいますよ。
もし、ダイアログの親にフレームウインドウを指定したとしたらどうなるでしょう?
ちょっと考えて思いつくのはそれぐらいでしょうか。
ダイアログは、モーダルでないとだめですか?
モードレスなら、親ウインドウの「thisポインター」を引き継げられると思います。
これ、ダイアログが無応答になった時点でキャプチャーウィンドウを確認して
みたら、ツリービューがマウスキャプチャーしちゃってますね。
で、ダイアログにマウスメッセージが届かない。(キーボード操作は可能)
たぶん、ツリーコントロールでは WM_RBUTTONDOWN のデフォルト処理が
マウスキャプチャーを開始するので、こういうことになるのだろうと...
pPopup->TrackPopupMenu(...);
の後にある、
CTreeView::OnRButtonDown(nFlags, point);
を削除すれば意図通りに動くと思います。
でも、WM_RBUTTONDOWN でやらなければならないというような
特別な理由がなければ、
http://support.microsoft.com/?scid=kb%3Ben-us%3B222905&x=12&y=17
の方法でコンテキストメニューを表示したほうがいいと思います。
#ツリーコントロールでの WM_CONTEXTMENU ってちょっと特殊みたいね
PATIOさん、ITOさん、rさん、ありがとうございます。
CTreeView::OnRButtonDown(nFlags, point); の削除で直りました。
Dialogベースで使用した時は問題無かったのですが、TreeCtrl 使用時に注意が必要と言う
ことですか。
やりたいことは、一般によく見られるツリーの各項目をクリックするとポップアップの
メニューがでて、プロパティやその他の処理を行うものです。
コンテキストメニューは知らなかったので、WM_RBUTTONDOWN や TVHITTESTINFO を使いなが
ら
ゴニョゴニョやってました。
「How To Display a Context Menu for CTreeCtrl」参考にさせて頂きます。
皆さん、ありがとうございました。