#pragma twice

KAB-studio > プログラミング > #pragma twice > 157 Version 8.15 通知メッセージの受け方

#pragma twice 157 Version 8.15 通知メッセージの受け方

前のページへ 表紙・目次へ 次のページへ

 Version 8.15
通知メッセージの受け方

今回は MFC の方の最後として、通知メッセージの受け方を説明します
ってゆーかそれが目的だったんだよね、確か
そう、このあと SimpleDialog の方に戻って、 MFC を使わないでツリー
ビューコントロールを操作する方法を解説するから
そのための準備か今回までってことね
そゆこと。まずはと……ツリーのアイテムの追加はこんな感じ

BOOL CMfcDialogDlg::OnInitDialog()
{
// 略。
    // TODO: 特別な初期化を行う時はこの場所に追加してください。
    HTREEITEM h1stItem
        = m_cMainTree.InsertItem( "1番目のアイテム" );
    m_cMainTree.InsertItem( "2番目のアイテム" );
    m_cMainTree.InsertItem( "1−1番目のアイテム", h1stItem );

    return TRUE;
}

ほいほい
次に、ダイアログエディタで貼り付けてあるツリービューコントロール 
IDC_TREE_MAIN の右クリックメニューから【イベント】を選んで
ボタンを押したときのメンバ関数を作るときと同じだね……
あ!
な、なに???
そうだ、それキャンセルして、【OK】ボタンで【イベント】選んで
ん? それがそのボタンを押したとき、でしょ?
そう、だから。今まで火美ちゃんは〈こうすればメンバ関数ができる〉
ってことでしか見てなかったけど、少し憶えたことあるからちょっと違う見
方できると思うよ
違う見方……あ、左側のとこに BN_CLICKED と BN_DOUBLECLICKED があ
る、これって通知メッセージだよね!
そう、通知メッセージ。 Version 8.10 ( No.152 ) でやったように、ボ
タンを押したときには WM_COMMAND と一緒に BN_CLICKED が通知メッセージ
として送られてきます
ここではいつも、 BN_CLICKED を選んで【追加と編集】してたよね
そうすると、 MFC を仕組みを使って、 WM_COMMAND が送られてきた時に 
BN_CLICKED とボタンの ID の IDOK が送られてきたらメンバ関数を読み込
むように
プログラムを作ってくれる!
そゆこと
……でも、その辺の仕組みってどうなってるの? なんか裏でこそこ
そ?
まだ難しいからもう少し先になるけど、これはマクロ使ってます
マクロ?
 BEGIN_MESSAGE_MAP とか DECLARE_MESSAGE_MAP がコードにあるでしょ
うんある。これがマクロ?
そう。これが実は結構長いプログラムに置き換えられます
そっか、マクロだからそういうこともできるんだ
この置き換えられたプログラムにはメッセージが送られてきて、この中に 
ON_BN_CLICKED とかのマクロを埋め込むと
ひっかかってメンバ関数が呼ばれる?
そゆこと。さっきのイベントのとか、 ClassWizard とか使うとこういう
マクロを VC がプログラムに書き込んでくれるんです
……ってことは、もうちょっと勉強すれば、この辺の仕組みも見て分かる
ようになる?
もちろん。その辺もちゃんと教えるからね
いつになるやら
ま、その辺は気長にね。話を戻して
ツリービューコントロールこのイベント?
そうそう、そっちの方の【イベントハンドラの新規作成】ダイアログを出
して
ほい。お、 NM_CLICK とかの通知メッセージと TVN_BEGINDRAG とかの通
知メッセージがある
 NM_ のは、 Version 8.11 ( No.153 ) で言った〈新しいコントロール〉
すべてに共通の通知メッセージ
マウスをクリックしたとかだね。 TVN_ はツリービューコントロールだけ
のってこと?
そう。これはコントロールごとに違うのがあるから。ちなみに、これが
MFC のだってことに注意
ん? 当たり前じゃない
もし MFC だけやってたら
あ、そういえば通知メッセージがここに出てるけど、通知メッセージのこ
とを知らなかったら……
 MFC は便利だけど、でもこういうふうに通知メッセージの知識は必要
だったりするから、何も分からなくても使えるってわけじゃないんだよね
ボタンの時は何も知らずに教えられたままに、だもんねー
時には MFC 使っててもこの辺の仕組みを知らないといけなかったりする
から
だからあたしはこういうことも教わってるわけね
そゆこと。じゃあ TVN_SELCHANGED を選んで【追加と編集】を選んで
ほい。 Sel Changed ってことは、選択してるアイテムを変えたときに送
られてくる通知メッセージ?
そう。他にも色々あるけど、これが分かりやすいと思って
ん、メンバ関数ができた。ボタンと同じね

void CMfcDialogDlg::OnSelchangedTreeMain
    (NMHDR* pNMHDR, LRESULT* pResult) 
{
    NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
    
    *pResult = 0;
}

注、長いから改行しました
でー、なんか引数難しいね。ポインタっぽいけど
そうだね……これは結構難しいかも。っていうより、むしろ MFC 使わな
い方でやった方が分かりやすかったかも
なんですとー!?
まぁとりあえずこっちで見ておこうか。まず第1引数の NMHDR 構造体の
ポインタ。これは WM_NOTIFY の LPARAM として渡されるもので、この中に
通知メッセージの各種情報が入ってます
……だけど

    NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;

ってなに? NMHDR って構造体が、 NM_TREEVIEW って……メッセージに
なってる?
これはかなり混乱の元かも。まず、 NM_TREEVIEW も構造体で、この中に
ツリービューコントロールの各種情報が入ってます
でも、 NMHDR と NM_TREEVIEW って構造体違うのにこんなことしていい
の?
これは大丈夫。 NM_TREEVIEW の最初のメンバ変数が NMHDR になってるか

???
んー、これはメモリ上のイメージが必要かもね。メモリ上に NM_TREEVIEW
構造体が置かれてます

[                 NM_TREEVIEW                  ]

この中には、最初に NMHDR 、次に UINT 、 TVITEM がふたつ、最後に 
POINT 構造体が入ってます

[[ NMHDR ][ UINT ][ TVITEM ][ TVITEM ][ POINT ]]

この TVN_SELCHANGED の場合、実際には WM_NOTIFY の LPARAM には 
NM_TREEVIEW へのポインタが渡されます。つまり、ウィンドウズがこの構造
体を持ってて、そのポインタだけ LPARAM に渡してくるってこと
それを NMHDR へのポインタにもできる……あー、つまり上のだと

[[ NMHDR ]]

って見るのと同じってこと? union みたく
そうそう、そういうこと。こういうのはホントは良くないんだけど、 
WM_NOTIFY の仕組みがそうなってるから
これはそうしなきゃ使えないわけねー
まぁ、これは MFC だから LPARAM じゃなくて NMHDR へのポインタが渡さ
れちゃうからこうなってるけど、 LPARAM から NM_TREEVIEW へのポインタ
にキャストしてからなら NMHDR へはメンバ変数として使えるから
そっちの方が安全っぽいね
で、この NMHDR にはツリービューコントロールのウィンドウハンドルと
か入ってるんだけど、今回は使いません
なんで?
このメンバ関数が呼ばれたってことは、どのツリービューコントロールの
通知メッセージって分かるから
あー
だからその辺は調べずに、直接 m_cMainTree でツリービューコントロー
ルを操作すればいいだけ。というわけで実際にやってみましょう

void CMfcDialogDlg::OnSelchangedTreeMain
    (NMHDR* pNMHDR, LRESULT* pResult) 
{
    NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;

    char pchText[256];
    TVITEM stTvItem;
    stTvItem.mask = TVIF_TEXT;
    stTvItem.hItem = pNMTreeView->itemNew.hItem;
    stTvItem.pszText = pchText;
    stTvItem.cchTextMax = 255;

    // 実際に受け取ります。
    m_cMainTree.GetItem( &stTvItem );
    TRACE( "%s\n", pchText );

    *pResult = 0;
}

あれ? どっかでみたよーな
 Version 8.13 ( No.155 ) の、アイテムの名前を取得するのとほとんど
同じ
違うのは…… TVITEM::hItem に入れてるとこだけだね
ここで NM_TREEVIEW の2番目の TVITEM に入ってる〈アイテムのハンド
ル〉を渡します
あ、おなじみの TVITEM だ
ふたつある TVITEM は、最初のは以前選択されてたアイテム、あとのは新
しく選択したアイテム
そういえば……こうやって面倒なことしてるってことは、この TVITEM の
pszText には、アイテムの文字列が入ってないんだ
入ってないんだよねー、残念ながら。ま、この方法自体は
分かってるから大丈夫だけどねー。最後の、っていうか第2引数の 
pResult は?
 LRESULT は API の型のひとつで、戻り値に使うもの
 result って〈結果〉って意味だもんね。 L は?
 LPARAM の L と同じ
 LPARAM の L ってなんだっけ
……教えてないかも。この話は長くなっちゃうからパス。この LRESULT 
のポインタを通して渡した値が、ウィンドウプロシージャの戻り値として返
されます
? 普通にこのメンバ関数の戻り値にすればいいんじゃないの?
実はイベントハンドラになるメンバ関数って戻り値は void って決まって
るんです
あらま。だからわざわざ引数で?
そゆこと。というわけで API だけのに戻ります!

/*
    Preview Next Story!
*/
さらば MFC ……でも結構めんどいとこもあったね
まぁ、 API でするときの勉強も兼ねてたからね
全部 MFC でやったら簡単? あ、構造体とか使わないから
アイテムの追加とかはかなり簡単
ってことは次回からまた大変ね……
とりあえずこんな感じ
うわ、コードが長い!
というわけで次回
< Version 8.16 API だけでツリーコントロール操作 >
につづく!
長くても、細かい部分の組み合わせなんだけどね
そう見えるように慣れるようにしないとね
そゆこと
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。