親ウインドウにメッセージをおくるには

解決


清原  2006-04-20 19:47:32  No: 61279  IP: 192.*.*.*

MFC Visual C++.NET  WindowXPで開発しています

CListCtrlから派生したクラスを作っています。
ですが、あるタイミングで親ウインドウに自作メッセージを送りたいんです

親ウインドウで  WM_NOTIFY  で処理すると思っていますけど、
でもうまくいってないんです。どうすればいいのでしょうか?
よろしくおねがいします

編集 削除
桑田  2006-04-21 05:23:40  No: 61280  IP: 192.*.*.*

親子関係はともかくとして、派生クラスから別な派生クラスを操作するなら、

http://homepage3.nifty.com/mitui707/VisualC/VCotherclassoperate.html/

というのがありました。
SDIで、ダイアログ→ダイアログとなっていますが、要は派生クラス → 派生クラスです。

はずしていたら、ごめんなさい。

編集 削除
subaru  2006-04-21 15:34:39  No: 61281  IP: 192.*.*.*

ユーザー定義のメッセージを送る場合は
SendMessageでWM_USER以降のメッセージを
送るのが簡単だし一般的ではないでしょうか。
(ユーザー定義のイベントのようなものを作りたいということなら
スマートではないかもしれませんが)

WM_NOTIFYで送ることもできないわけではないですが
自作コントロールでもないですし勝手に通知コードを
定義しても大丈夫かというとわかりません。

編集 削除
通りすがり  2006-04-21 19:09:04  No: 61282  IP: 192.*.*.*

WM_USERに関して補足

送り先がコモンコントロール等の場合には既存のメッセージと被る可能性があるので、WM_APP以降にすべきです。
WM_USER+nを使うのはプライベートなウインドウのみにしておきましょう。
(WM_USER+nなメッセージがいろいろ存在していますので)

MSDNより抜粋
WM_USER through 0x7FFF Integer messages for use by private window classes. 
WM_APP through 0xBFFF Messages available for use by applications.

編集 削除
subaru  2006-04-21 20:26:02  No: 61283  IP: 192.*.*.*

>送り先がコモンコントロール等の場合には既存のメッセージと被る可能性があるので、WM_APP以降にすべきです。
たしかに親ウインドウがコントロールでないということが
この質問からはわかりませんね。。。
同様の理由から「CListCtrlから派生したクラス」というものに再利用性を求めるなら
これらの方法はオススメではありません。

編集 削除
清原  2006-04-21 23:53:26  No: 61284  IP: 192.*.*.*

この前は問題をはっきりにしていなくて申し訳ないんですが…
実は…

CEdit コントロールは  テキストが変更されたら
EN_CHANGEメッセージが自動的に送られて、
必要によって、親ウインドウにON_EN_CHANGEメッセージを捕まえて
処理することができます.

僕が今作ってるクラスは CListCtrlクラス から  派生して、
あるタイミングでCEditなどのコントロールのように、
親ウインドウにメッセージを送って、
親ウインドウがこのメッセージを捕まえて、
それに応じて処理することができるようにしたいんです。

以下は僕のコ−ドですが

#define UM_MYMSGTOPARENT  WM_USER+100

class CMyListCtrl:public CListCtrl
{
 //......省略
 CWnd* m_Parent;   //親ウインドウ
 afx_msg void OnOneFunction();
};


void CMyListCtrl::OnOneFunction()
{
  //ここのm_Parentウインドウが有効なウインドウです
  NMHDR  nmhdr;
  nmhdr.hwndFrom = this->GetSafeHwnd();
  nmhdr.idFrom = this->GetDlgCtrlID();
  nmhdr.code =  UM_MYMSGTOPARENT ;
  m_Parent->SendMessage(WM_NOTIFY,(WPARAM)GetDlgCtrlID(),
                        (LPARAM)&nmhdr);
}

/////////////////////////////////////

そして親ウインドウで


BOOL CParentWnd::OnNotify(WPARAM wParam,LPARAM lParam,LRESULT* lR)
{
  if((UINT)wParam == IDC_MYLISTID)
  {
      // ここで処理
  }
}

ちょっと自分で試したんだが
こうしては大丈夫なのかな?もっといい方法があるのかな?

編集 削除
清原  2006-04-21 23:56:08  No: 61285  IP: 192.*.*.*

すみません、

ステートメントひとつ忘れちゃった:
return CDialog::OnNotify(wParam,lParam,lR);

編集 削除
subaru  2006-04-22 12:52:55  No: 61286  IP: 192.*.*.*

>#define UM_MYMSGTOPARENT  WM_USER+100
この定義は通知コードとして安全に使えるものでしょうか?
たしかにWM_NOTIFYを送ることはできるでしょうが
問題はどんな通知コードを送るかですね。
おそらくWM_NOTIFYはサブクラス化されたウインドウから
ユーザー定義の通知コードを増やすことを想定してないので、
WM_APPに相当するような定数は用意されてないのかもしれません。

今回の場合は少なくとも
NM_FIRST〜NM_LAST
LVN_FIRST〜LVN_LAST
は避けなければならない感じでしょうか(?)

>ちょっと自分で試したんだが
>こうしては大丈夫なのかな?もっといい方法があるのかな?
単に親ウインドウ側で処理したいと仮定すると
別のアプローチとしては
JAVAのイベントリスナーのような仕組みを用意するとか、
CMyListCtrlのイベントを仮想関数で定義する
(実装はCParentWndのインナークラスにでもする)
とかの方法があると思います。

編集 削除
清原  2006-04-22 18:06:01  No: 61287  IP: 192.*.*.*

えっと、やはりちょっとわからないところがあるんだけど、


どうすれば避けるのか分からないんです:
>NM_FIRST〜NM_LAST
>LVN_FIRST〜LVN_LAST

単にこう定義しては済まないんでしょう:
  #define UM_MYMSGTOPARENT WM_APP + 1000    

昨日のコード は わけも分からなく 正しく 行けました。

>BOOL CParentWnd::OnNotify(WPARAM wParam,LPARAM lParam,LRESULT* lR)
>{
>  if((UINT)wParam == IDC_MYLISTID)
>  {
>     // ここで処理
      // ヘッダーにUM_MYMSGTOPARENTが定義されてます。
      // このヘッダーもインクルードされています

      if( ((NMHDR*)lParam)->code == UM_MYMSGTOPARENT )
      {
           AfxMessageBox("メッセージが届いた!");
      }
>  }
>  return CDialog::OnNotify(wParam,lParam,lR);
>}


今日も  MSDN  を探してみたら、こういう作り方はなさそうだ、
ON_NOTIFY_REFLECT が 独自のメッセージ  を  親ウインドウに送信できるそうですが、
試してみたら、失敗しました….  メッセージが届いてなかったそうだ。
//////////////////////////////////////////////////////////////////////


>単に親ウインドウ側で処理したいと仮定すると
>別のアプローチとしては
>JAVAのイベントリスナーのような仕組みを用意するとか、
>CMyListCtrlのイベントを仮想関数で定義する

そうですね、この前もいろいろ考えてたんだけど、今作っているクラスは、
CListCtrlの拡張クラスで、通用性が重要なんですが、
CWndクラスに  別の関数を  添加できないから,
インタクラスとかイベントリスナーとかはちょっと無理ですが…

編集 削除
清原  2006-04-22 18:06:21  No: 61288  IP: 192.*.*.*

えっと、やはりちょっとわからないところがあるんだけど、


どうすれば避けるのか分からないんです:
>NM_FIRST〜NM_LAST
>LVN_FIRST〜LVN_LAST

単にこう定義しては済まないんでしょう:
  #define UM_MYMSGTOPARENT WM_APP + 1000    

昨日のコード は わけも分からなく 正しく 行けました。

>BOOL CParentWnd::OnNotify(WPARAM wParam,LPARAM lParam,LRESULT* lR)
>{
>  if((UINT)wParam == IDC_MYLISTID)
>  {
>     // ここで処理
      // ヘッダーにUM_MYMSGTOPARENTが定義されてます。
      // このヘッダーもインクルードされています

      if( ((NMHDR*)lParam)->code == UM_MYMSGTOPARENT )
      {
           AfxMessageBox("メッセージが届いた!");
      }
>  }
>  return CDialog::OnNotify(wParam,lParam,lR);
>}


今日も  MSDN  を探してみたら、こういう作り方はなさそうだ、
ON_NOTIFY_REFLECT が 独自のメッセージ  を  親ウインドウに送信できるそうですが、
試してみたら、失敗しました….  メッセージが届いてなかったそうだ。
//////////////////////////////////////////////////////////////////////


>単に親ウインドウ側で処理したいと仮定すると
>別のアプローチとしては
>JAVAのイベントリスナーのような仕組みを用意するとか、
>CMyListCtrlのイベントを仮想関数で定義する

そうですね、この前もいろいろ考えてたんだけど、今作っているクラスは、
CListCtrlの拡張クラスで、通用性が重要なんですが、
CWndクラスに  別の関数を  添加できないから,
インタクラスとかイベントリスナーとかはちょっと無理ですが…

編集 削除
subaru  2006-04-24 10:41:33  No: 61289  IP: 192.*.*.*

>どうすれば避けるのか分からないんです:
>>NM_FIRST〜NM_LAST
>>LVN_FIRST〜LVN_LAST
HDN_FIRST〜HDN_LASTもありましたね。

>単にこう定義しては済まないんでしょう:
>  #define UM_MYMSGTOPARENT WM_APP + 1000    
この場合のWM_APPはまったく無意味な値としか思えませんが
他の通知コードと重複していなければ正常に動作するのでしょう。

>今日も  MSDN  を探してみたら、こういう作り方はなさそうだ、
>ON_NOTIFY_REFLECT が 独自のメッセージ  を  親ウインドウに送信できるそうですが、
>試してみたら、失敗しました….  メッセージが届いてなかったそうだ。
あまり詳しくないんですが普通はON_NOTIFYじゃないのかな?

編集 削除
清原  2006-04-24 19:32:56  No: 61290  IP: 192.*.*.*

subaru さん、
大変ありがとうございますm(_ _)m 、作り方が大体わかりました。
やっぱON_NOTIFYですね。
どうもありがとう。

編集 削除