Version 9.03
メニューを操作しよう!
「今回は、実際にプログラム側でメニューを操作します」
『おー。でも、難しい?』
「火美ちゃんはどう想像してる?」
『んー、前にツリービューコントロールみたいだって言ってた気がするし、
似たような感じなんじゃないの?』
「操作自体は似てないけど、でも同じ感じかもね。だから大丈夫だと思う
よ。じゃあ、まずは…… CMainFrame::OnCreate() ってメンバ関数があるで
しょ、それを表示して」
『ほいほいほい。 ClassView でダブルクリックしてっと』
「メニューはフレームウィンドウに着いているものだから、 SDI の場合に
はメニューの操作はフレームウィンドウでするのが普通ってことで、フレー
ムウィンドウのメンバ関数でします」
『? 〈 SDI の場合〉ってことは、 MDI の場合には違うの?』
「うん、 MDI の場合にはひとつのウィンドウの中にいっぱいファイルを開
けるでしょ」
『専門用語でいうとこのドキュメントね』
「そうそう。そのドキュメントごとに違うメニューを用意できるんだよね」
『へー』
「だから SDI の場合の話ってことで。で、これからするのは、最初にメ
ニューアイテムを追加するっていうもの」
『それってつまり、リソースの方を操作しないで、プログラムでってこと
ね』
「もちろん」
『 InitDialog() でツリービューコントロールにアイテム追加したようなの
と同じってことだよね』
「そうそう、それと同じこと。でも、ダイアログじゃないから微妙に違って
きます。まず、 CDialog::InitDialog() じゃなくて、
CMainFrame::OnCreate() で追加します」
『ウィンドウが作られる直前に呼ばれるのがそれなのね』
「一応ひと通り見ておくと……」
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
if (!m_wndToolBar.CreateEx
(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY
| CBRS_SIZE_DYNAMIC) ||
!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
{
TRACE0("Failed to create toolbar\n");
return -1; // 作成に失敗
}
if (!m_wndStatusBar.Create(this) ||
!m_wndStatusBar.SetIndicators(indicators,
sizeof(indicators)/sizeof(UINT)))
{
TRACE0("Failed to create status bar\n");
return -1; // 作成に失敗
}
// TODO: ツール バーをドッキング可能にしない場合は以下の3行を削
// 除してください。
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar);
return 0;
}
『これって最初からあったコードだよね』
「そう、 AppWizard が用意してくれたコード。今回は深くは見ていかない
けど、なんとなくわかるでしょ?」
『うん、ツールバーとステータスバー作ってるみたいだね』
「ツールバーもステータスバーも、こういう形でプログラムとして書かれて
るから作られて操作できるってことだね」
『いつかはあたしも、ってヤツ?』
「まーね。さて、この return 0 の直前に、こういうコードを追加して」
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
// 略。
// メニューバーを取得します。
CMenu *pcMenuBar = GetMenu();
// メニューアイテムをインサートします。
pcMenuBar->InsertMenu
( 0
, MF_BYPOSITION | MF_STRING
, ID_FILE_OPEN
, "ファイルを開く(&O)"
);
return 0;
}
『お、メニューっぽい。ん? CMenu ってことは、 MFC のクラス?』
「そう、いつも通り SDK だけでも MFC 使ってもメニューを操作できるけ
ど、まずは MFC 使って簡単に操作してみます」
『いつものパターンね』
「まず、 CWnd::GetMenu() でメニューバーを指す CMenu へのポインタを取
得します」
『あ、これは CWnd のメンバ関数なんだ』
「 API 版もあるけど、その場合にはメニューバーを持ってるウィンドウの
ハンドルを渡します」
『この場合にはフレームウィンドウね』
「それに、戻り値も HMENU っていう、メニューのハンドルが返ってきま
す」
『 MFC だと CMenu のポインタなのね。あれ? なんでポインタなんだっ
け』
「 Version 7.03 ( No.123 ) を思い出して。 CMenu も CDC とか CWnd と
かと同じで中にハンドルを持ってるから」
『 HMENU ね。そっか。 CMenu 自体が返ってくるとそれが消えたら中の
CMenu そのものもなくなっちゃうから……メニューがなくなっちゃう?』
「あとでそれ試してみようか、実際になくなっちゃうから」
『なくなっちゃうと困るからポインタが返ってくるわけね。で、そのポイン
タで…… CMenu::InsertItem() ってメンバ関数でメニューアイテムを追加
するわけね』
「そうそう。この辺の感覚は」
『ツリービューコントロールとかと似てるかも』
「それぞれの引数について見ておこうか。まず」
( 0
「は、メニューアイテムを挿入する位置」
『 0 だと先頭?』
「そう。この辺は他のと統一されてないからややこしくて、最後に追加する
ときは -1 を渡すって決まりになってます」
『ホント、ややこしい……。次の』
, MF_BYPOSITION | MF_STRING
『はフラグね』
「 MF_BYPOSITION は、第1引数の意味を決めるもの。実は、位置じゃなく
て ID でどこに挿入するかを決めることができるんです」
『 ID ?』
「メニューアイテムの。 ID_FILE_OPEN とかのこと」
『あー。でもそれって分かりにくくない?』
「そう思うよ。だからあまり使わないと思う……。もうひとつの MF_STRING
は、今度は第4引数の意味を決めるので、メニューアイテムの文字列を渡す
っていう意味」
『……それも、それ以外って思い付かないんだけど……』
「前に【オーナードロー】って教えたことあるでしょ」
『 Version 7.17 ( No.137 ) ね。あ、そっか、オーナードローだと自分で
文を書かなきゃいけないから』
「第4引数で渡す文字列が関係なくなって、代わりの他のものを渡さなきゃ
いけなくなるってこと。ま、それは今回はぱす。あと MF_SEPARATOR を渡す
と」
『あ、セパレーターってことは横棒ね。そりゃ文字列関係ないね……』
「そゆこと。第3引数の」
, ID_FILE_OPEN
『これはさっき言ってたメニューアイテムの ID ね』
「そう、今回はテストってことで【ファイルを開く】の ID と同じものを指
定します」
『追加したメニューを選んだらファイルダイアログが出るってわけね』
「そゆこと。最後の」
, "ファイルを開く(&O)"
『これがメニューアイテムに出ると。ここで、ニーモニックとやらも指定で
きるわけね』
「この辺はリソースで操作するときと同じだから」
『んじゃ実行! おー、メニューバーの最初に【ファイルを開く(O)】が
入ってる! 選ぶとファイルダイアログが出る!』
「って感じに、結構簡単にメニューアイテムは追加できるわけです」
『ホント、結構簡単。構造体とか使わないし』
「けど」
『けど?』
「と、それは次回に持ち越し。最後にメニューを消しちゃうっていうのを見
ておきましょう」
『さっき言ってたのね』
「今のメニュー取得とインサートのところを、次のコードに置き換えて」
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
// 略。
CMenu *pcMenuBar = GetMenu();
CMenu cDeleteMenu;
cDeleteMenu.Attach( pcMenuBar->GetSafeHmenu() );
return 0;
}
『んーと、最初の1行はさっきと同じね。次が、ポインタじゃない CMenu
を作って、最後に CMenu::Attach() でメニューハンドル持たせるわけね』
「メニューハンドルの取得は CMenu::GetSafeHmenu() でできるから」
『 CWnd::GetSafeHwnd() のメニュー版ね。で、このまま放っておけば、自
動的にメニューハンドルが削除されちゃうわけね』
「じゃ、実際に試してみて」
『ほい。うわぁ!! タイトルバーの下が……なんか透けてるってゆー
か、シュールってゆーか……』
「というふうに、問答無用でメニューバーが削除されちゃうから」
『メニューバーなんてまず消さないんだから、エラーになって何も起きない
とかなればいいのに』
「そういうところは不親切だから、くれぐれもこういうことしないように気
をつけてね」
/*
Preview Next Story!
*/
『意外とあぶなっかしーのねー』
「こういう API のルールには、慣れて自分で気を付けるしかないかな」
『そういうのって結構ある?』
「あるよ、たとえばメニューバーとポップアップメニューの違いとか」
『それって大きな違いあるんだー』
「というわけで次回」
< Version 9.04 メニューの構造 >
『につづく!』
「正直、この辺は MSDN の英文をしっかり読めないときついかもね……」
『水希ちゃん、きつかった頃の表情が出ちゃってるよ』