Version 9.04
メニューの構造
「前回はメニューにアイテムを追加してみました」
『でも、追加したのってメニューバーにだよね。なんか違うよーな』
「だね、だから今回は【ファイル】サブメニューの中に追加してみます」
『って感じに別にするってことは、ちょっと難しいってこと?』
「っていうよりはちょっと複雑ってくらい。ま、まずはコードから」
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
// 略。
// メニューバーを取得します。
CMenu *pcMenuBar = GetMenu();
// 【ファイル】サブメニューを取得します。
CMenu *pcFileMenu = pcMenuBar->GetSubMenu( 0 );
// メニューアイテムをインサートします。
pcFileMenu->InsertMenu
( -1
, MF_BYPOSITION | MF_STRING
, ID_FILE_OPEN
, "ファイルを開く(&O)"
);
return 0;
}
『あんま違わないね』
「だね、一番の違いは」
// 【ファイル】サブメニューを取得します。
CMenu *pcFileMenu = pcMenuBar->GetSubMenu( 0 );
「の行が追加されてること」
『わざわざそんなことしてる理由は?』
「最初に CWnd::GetMenu() で取得したメニュー」
『 pcMenuBar ね』
「これは、メニューバーだけ。つまり【ファイル】サブメニューや【編集】
サブメニューは含まれてません」
『横一列だけってことね』
「だから、このメニューバーから【ファイル】サブメニューを取得する必要
があるんです」
『それが CMenu::GetSubMenu() なわけね。 0 は最初の、つまり【ファイ
ル】サブメニューのってこと?』
「そゆこと。それで取得した pcFileMenu が【ファイル】サブメニュー一列
分」
『一列分……そっか、 CMenu はメニューバーもポップアップメニューも、
一列ずつだけなんだ』
「そう、だからもし【ファイル】サブメニューにさらにサブメニューがあっ
たら」
『 CMenu::GetSubMenu() でその位置を指定して、また CMenu のポインタ受
け取って、ってなるわけね』
「そういう仕組みになってるから、 CMenu::GetSubMenu() や
CMenu::InsertMenu() で位置を指定するのが簡単になってるかな。メニュー
全体だと」
『かなり大変そうね。そういえば、次の CMenu::InsertMenu() のとこも』
pcFileMenu->InsertMenu
『って、その pcFileMenu になってるね』
「アイテムを追加したいサブメニューで CMenu::InsertMenu() を呼べば」
『そのサブメニューに追加されるわけね』
「ちなみに CMenu::InsertMenu() の第1引数に -1 を渡してるから」
『ホントだ。 -1 だと最後に追加なんだよね。あ、ビルドして実行っと。う
ん、最後に追加されてる』
「こんな感じに、メニューは一列ごとに管理されてるってことを解ってもら
えればいいかな」
『これって、 CMenu のじゃないんだよね』
「そう、 MFC のじゃなくて、ウィンドウズのシステムとしてそうなってる
から。だから HMENU を直接使ってもこうなるからね」
『その辺はいつものパターンね』
「さて、今のをもう少し理解してもらうために、今度はメニューを作ってみ
ます」
『メニューを作る!』
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
// 略。
// 新しくサブメニューを作成します。
CMenu cNewSubMenu;
cNewSubMenu.CreatePopupMenu();
cNewSubMenu.InsertMenu
( -1
, MF_BYPOSITION | MF_STRING
, ID_FILE_OPEN
, "ファイルを開く(&O)"
);
// メニューバーを取得します。
CMenu *pcMenuBar = GetMenu();
pcMenuBar->InsertMenu
( -1
, MF_BYPOSITION | MF_STRING | MF_POPUP
, (UINT)( cNewSubMenu.GetSafeHmenu() )
, "新規サブメニュー (&N)"
);
// CMenu の管理から解放します。
cNewSubMenu.Detach();
return 0;
}
『って、さっきとあんまり違わないね。えっと、まず最初に……今度はポイ
ンタじゃない CMenu を作ってるね』
「元々あるメニューじゃない、新しいメニューを作るからね」
『で、 CMenu::CreatePopupMenu() 、これでメニューを作ってるんだ』
「あ、そうそう、 CMenu のメンバ関数一覧って見てみて」
『ほい。あ、 CMenu::CreateMenu() ってのもあるなんで Create なのがふ
たつもあんの?』
「それは」
CreateMenu() : メニューバーを作る
CreatePopupMenu() : ポップアップメニュー(サブメニュー)を作る
「ってこと」
『なるほど、メニューバーとポップアップメニューは作り方も違うんだ』
「この辺も別物ってことだね。そのあと、いつもの CMenu::InsertMenu()
でメニューアイテムを追加します」
『この辺は同じね』
「で、この時点ではこのポップアップメニューはまだ表示されないから、こ
れをメニューのサブメニューとしてくっつける必要があります」
『それがそのあとのところね。えっと、次の CWnd::GetMenu() でメニュー
バー拾って、そのあとの』
pcMenuBar->InsertMenu
( -1
, MF_BYPOSITION | MF_STRING | MF_POPUP
, (UINT)( cNewSubMenu.GetSafeHmenu() )
, "新規サブメニュー (&N)"
);
『 MF_POPUP ってフラグ、ポップアップメニューってこと?』
「そゆこと。この CMenu::InsertMenu() で、次のサブメニューを表示させ
るメニューアイテムを追加してます」
『サブメニューを追加するんじゃなくて、メニューアイテムを追加す
る……』
「 Version 9.02 ( No.163 ) の【ポップアップ】がオンになったメニュー
アイテムを追加するってこと。で、第3引数で」
『さっき作ったメニューのハンドル渡してるんだね』
「普段は ID を渡すんだけど、サブメニューをくっつける場合にはここにそ
のメニューハンドルを渡します」
『なんかキャストしてるしちょっとヤな感じ……』
「確かにね。 CMenu のポインタを渡せるようにしてくれるとよかったんだ
けど」
『で……えーっとまとめると、メニューバーの最後にアイテムを追加して、
そのアイテムは【ポップアップ】で、そこにさっき作ったポップメニューを
くっつけるために、そのメニューのハンドルを渡してるわけね』
「ちょっと混乱するかもね」
『まー慣れれば大丈夫かな。と、最後の』
// CMenu の管理から解放します。
cNewSubMenu.Detach();
『ってなに?』
「あ、その前にビルドして実行してみて」
『ほい。うん、メニューバーの最後に【新規サブメニュー】が追加されて、
それを選ぶと……おお、ちゃんと新しく作ったサブメニューが! アイテム
ひとつだから見栄え悪いけど』
「これが普通の動作。で、上の CMenu::Detach() 呼んでるところをコメン
トアウトすると」
『ビルドして実行。あら、選んだらエラーになっちゃった』
「これは、せっかく作ってくっつけたポップアップメニューが削除されてる
から」
『あ! そうよ! だって cNewSubMenu ってポインタじゃないじゃん、消
えるときに持ってるメニュー消しちゃうじゃない』
「そう、だから」
『 CMenu::Detach() 呼んで、消さないようにしてるわけね。でも……なん
か変くない?』
「だね、普通はこの cNewSubMenu を CMainFrame のメンバ変数にするだろ
うし」
『それならずっとあるから大丈夫なわけね』
「まぁ僕なら CMenu 使わないけど」
『 HMENU 直接なら、削除される心配もないわけね』
「必要な時に GetMenu() とかでいつでも取得できるしね。最後に、さっき
言ったメニューバーとポップアップメニューの違いを見ておこうか」
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
// 略。
// 新しくサブメニューを作成します。
CMenu cNewSubMenu;
cNewSubMenu.CreatePopupMenu();
cNewSubMenu.InsertMenu
( -1
, MF_BYPOSITION | MF_STRING
, ID_FILE_OPEN
, "ファイルを開く(&O)"
);
// メニューバーにくっつけます
SetMenu( &cNewSubMenu );
// CMenu の管理から解放します。
cNewSubMenu.Detach();
return 0;
}
「メニューバーにメニューをセットするときは CWnd::SetMenu() を使いま
す。すると」
『げ、メニューバーが変! また透けてるみたい! しかも固まってるし』
「というわけで使えなくなります。ちなみに CreatePopupMenu() のところ
を CreateMenu() に変えれば」
『あ、今度は大丈夫』
「というわけ。もちろん、今度はポップアップメニューとしては使えないけ
どね」
/*
Preview Next Story!
*/
『ポップアップメニューとメニューバー、ねぇ』
「でも聞けばそんなに難しくないでしょ」
『訊けばね』
「でもここからは聞いてもちょっと複雑かも」
『げげ』
「というわけで次回」
< Version 9.05 右クリックメニューを表示する! >
『につづく!』
「でも右クリックメニュー自体は結構面白いかもね」
『じゃーその面白いとこだけする!』
「じゃあプログラミングする意味ないじゃない」