Version 5.28
イベント=メッセージ
「さてさてさて! ウィンドウを操作するときはメッセージを送る!」
『リストボックスに文字列追加するのに LB_ADDSTRING を送りました!』
「しかし! メッセージは単にそれだけじゃなく」
『ぼ、ボタン押したらメッセージ送られてくるの!?』
「そうです。ってゆーか……〈イベント〉って憶えてる?」
『何かが起きた、ってことだよね。ボタン押されたのもイベントだよね』
「そう。で、そのイベントはすべて、メッセージとして送られてきたものな
のです」
『……すべて?』
「すべて。見た方が早いかもね。 Spy++ を起動して、照準を〈てすと〉ダ
イアログに合わせて」
『ほい』
「【ウィンドウ検索】ダイアログの一番下に【表示】っていう囲いがあるで
しょ。それを【メッセージ】にして」
『ほい。んで OK ボタン?』
「押したらメニューの【メッセージ】−【オプション】」
『ほい。ダイアログ出たよ』
「【メッセージ】ページにして」
『ほい。左にリストボックス、右はチェックボックスいっぱい』
「左の【表示するメッセージ】っていうの眺めてみて」
『なーんかいっぱいあるねー……これ全部メッセージ?』
「そう、全部メッセージ。 LB_ADDSTRING もあるよ?」
『ホントだ……これ全部でいくつあるんだろ』
「じゃ、その下の【すべて選択】を選んで」
『あ、これで分かるんだ。…… 849 メッセージぃ!? そんなにあるの?』
「たとえば最初の方に BM_ っていうのあるでしょ。これはボタンのメッセー
ジ」
『そっか、コントロールの数だけメッセージがあるんだね』
「もちろん他のもあるけどね。とりあえずこの状態で OK して」
『ほい』
「で、〈テストダイアログ〉をちょちょっと」
『ちょちょっと……うわーっ!! Spy++ になんかすんごくいっぱい出て
きたっっ!!』
「これ全部メッセージ」
『こ、これ全部!? ってことはなに? ダイアログひとつでこんだけの
メッセージばばばって処理しちゃってるわけ!?』
「処理してるかどうかは別として、受け取ってはいるわけ」
『す、すごい……』
「じゃ、またメニューの【メッセージ】−【オプション】を選んで」
『ほい』
「【すべてクリア】で全部の選択を解除してから、【表示するメッセージ】
の中から WM_MOUSEMOVE を選んで」
『 W だから下の方…… WM_MOUSEMOVE あった』
「 OK して、ついでに【メッセージ】−【クリア】を選んで」
『あ、メッセージ消えた』
「さて。今回は数あるメッセージの中から、 WM_MOUSEMOVE っていうメッ
セージが送られてきた時だけ Spy++ に表示されます」
『 WM_MOUSEMOVE って言うくらいなんだから、マウスが動くと……メッセー
ジが送られてきた!』
「マウスをちょっと動かすだけで」
『次々と送られてくる! たったこれだけで送られてくるんだから、そりゃ
いっぱい送られてくるわよねー。あ、 xPos と yPos って、座標も表示され
るんだ』
「これは LPARAM の値」
『 LPARAM ってなんだっけ』
「前回やったでしょ、 SendMessage() 」
『そうそう、その関数の引数だったね』
「 WM_MOUSEMOVE が送られるとき、その引数にマウスの位置が渡されるわけ。
MSDN の WM_MOUSEMOVE を見てみて」
『ほい。 LOWORD とか HIWORD とか分かんないけど……』
「 LPARAM には x 座標と y 座標両方が入ってて、そのうちひとつだけを取
り出すのに LOWORD とかを使ってるってこと」
『んー?』
「まぁそれは置いといて。つまり、ホントは LPARAM として送られてくるん
だけど、それを Spy++ が中身の分かる形で表示してくれてるってこと」
『便利ってことね』
「というわけでつまり」
『つまり、メッセージってホントにいっぱい送られて来てるってことだよね』
「そして、こういう〈マウスカーソルが動く〉っていうことも〈イベント〉
のひとつってこと」
『え? じゃあ、この〈マウスが動く〉っていうので……たとえば
CFileTestDlg::OnBtnShow() が呼ばれる、みたいなことできるってこと?』
「そうだよ。メニューの【表示】−【ClassWizard】で」
『ダイアログ出たよ』
「【メッセージ マップ】のページで、【クラス名】が CFileTestDlg 、
【オブジェクト ID 】も CFileTestDlg なのを確認してから、【メッセージ】
の下の方を……」
『 WM_ っていうのいっぱいあるね、これがメッセージなんだよね。あ、
WM_MOUSEMOVE があった!』
「それを選択して【関数の追加】ボタン押して【コード編集】押して」
『ほいほい。あ、 CFileTestDlg::OnMouseMove() って関数できた!』
void CFileTestDlg::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: この位置にメッセージ ハンドラ用のコードを
// 追加するかまたはデフォルトの処理を呼び出してください
CDialog::OnMouseMove(nFlags, point);
}
『マウスを動かすとこれが呼ばれるの?』
「呼ばれるよ。こう書き換えて」
void CFileTestDlg::OnMouseMove(UINT nFlags, CPoint point)
{
TRACE
( "CFileTestDlg::OnMouseMove: %d, %d\n"
, point.x, point.y );
CDialog::OnMouseMove(nFlags, point);
}
『 CPoint ……ってまー点って意味なんだろうけど』
「 CPoint は MFC のクラスで、〈点の座標〉を格納するためのもの。あと
で MSDN 見といてね」
『んじゃビルドして実行。うわ、マウス動かすだけでアウトプットウィンド
ウに出てくる!』
CFileTestDlg::OnMouseMove: 251, 194
CFileTestDlg::OnMouseMove: 253, 193
CFileTestDlg::OnMouseMove: 255, 193
...
「でもダイアログの上じゃないと出ないでしょ」
『ホントだ、リストボックスの上でも出ない』
「これはダイアログのメッセージしか処理しないからね」
『これ見ると、 x と y にマウスの位置が入ってるってこと?』
「そういうこと。 Spy++ に似てるでしょ」
『うん似てる。でもこれも、 LPARAM っていうのをなんか処理してるんだよ
ね』
「じゃあ見てみましょう。今のの TRACE() の所でブレークポイント」
『ほい』
「ステップアウトのボタン押して。〈中カッコから出る〉っていうの」
『これ押すとどうなるの?』
「今の関数から抜けて、呼び出してる部分を表示するの。つまり〈何度もス
テップインし続けて関数から抜けるとこまで行く〉っていうのを自動的にし
てくれてるってこと」
『ようするに CFileTestDlg::OnMouseMove() を呼んでる部分が出るってこ
とね。ぽちっと』
BOOL CWnd::OnWndMsg
(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
(略)
case AfxSig_vwp:
{
CPoint point((DWORD)lParam);
(this->*mmf.pfn_vwp)(wParam, point);
break;
}
(略)
}
『……なんか、むっちゃ、むっちゃ難しいんですけど!』
「うん、これはかなり難しいね。とりあえず、この関数の引数を見てみて」
『あ、ウィンドウプロシージャっていうのに似てる!』
「実際そう。これが MFC の実質的なウィンドウプロシージャってことかな」
『ってことは、 WM_MOUSEMOVE なら lParam ってのにマウスの位置が入って
るんだ』
「で、 message に WM_MOUSEMOVE が入ってると、この case に入ります」
『 case って…… Ver 2.9 ( No.020 ) でやったね。整数値で if みたいな
のができるのだね。……でもそう考えると、この AfxSig_vwp ってへんてこ
なのが』
「 WM_MOUSEMOVE って意味なんだよね、実は」
『ま、 WM_MOUSEMOVE でこん中に入るってことは分かったけど。あ、それで
次の CPoint point((DWORD)lParam); ってとこで lParam のを CPoint に入
れてるんだ』
「これがあるから、 CFileTestDlg::OnMouseMove() は CPoint で簡単にマ
ウスの座標を取得できるんです」
『してくれなかったら?』
「自分でこいうことして lParam から取り出さないとダメ」
『面倒ね……』
「で、次の (this->*mmf.pfn_vwp)(wParam, point); で
CFileTestDlg::OnMouseMove() を呼び出してます」
『どうやってもそう読めないんだけど……』
「ま、この辺はどうでもいいんだわ。あと4回ステップアウトして」
『ほいほいほいほい。 AfxWndProcBase() っていう関数……あ、この前の関
数だ!』
「これがホントのウィンドウプロシージャ。つまり!」
『つまり?』
「 MFC だって、ウィンドウプロシージャが付いてて、メッセージ送られて
きて、それを処理してるんだってこと」
『で、 CFileTestDlg::OnMouseMove() が呼ばれるまでに複雑なことがなん
かされてるってことね』
「そう、この辺をこんなふうに便利にするにはかなり面倒なシステムが必要
なんだよね」
『 MFC も苦労してるのねー』
「そのおかげで、 CPoint にマウスの座標が入ってて、簡単に処理できるよ
うになってるってこと」
『ふーん』
「そして!」
『そして?』
「前回の話に戻りましょう。この前火美ちゃんは」
『 SendMessage() みたいなのじゃなくて、メンバ関数直接呼ぶみたいな方
がいいのにって言ったんだけど……』
「このウィンドウプロシージャの仕組みはウィンドウズそのもののシステム
と深く関わってて、これナシにじゃメッセージを受け取れないんです」
『ようするに、ウィンドウプロシージャなしじゃイベントの処理できないか
ら、このウィンドウプロシージャって仕組みは変えられないんだよね』
「そういうこと。で、それじゃ不便だから」
『 MFC はその辺を便利になるようにしてて、だからメンバ関数が呼ばれて
簡単にってなってるんだよね』
「そういうこと」
『結局は、いつものパターンね……』
「あ、そうだ、 CFileTestDlg::OnMouseMove() はテスト用だから削除しと
きましょう」
『ただ削除しちゃえばいいの?』
「ダメダメ。まず ClassWizard 表示して、さっきみたいに WM_MOUSEMOVE
を選択してから【関数の削除】ボタン押して」
『ほい。ダイアログ出たよ?』
「【はい】押して【OK】押したら、 CFileTestDlg::OnMouseMove() の方も
削除してOK」
『削除してビルドっと、うん大丈夫』
/*
Preview Next Story!
*/
「さて次回でコントロール編最終回!」
『長かったねぇ』
「今回はちょっと面白かったでしょ?」
『別にそーゆーわけじゃないけどぉ……』
「ふふん? でも色々試してみてるみたいだけど」
『確かにまー、色々 API 使ってみたりしてるけど……』
「いい兆候だねー」
『というわけで次回』
< Version 5.29 ウィンドウとコントロールのまとめ >
「につづく!」
『昨日は、ファイルを削除する API 試してみたりとか……』
「ま、まさか!!」