#pragma twice

KAB-studio > プログラミング > #pragma twice > 164 Version 9.03 メニューを操作しよう!

#pragma twice 164 Version 9.03 メニューを操作しよう!

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

 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 の英文をしっかり読めないときついかもね……
水希ちゃん、きつかった頃の表情が出ちゃってるよ
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。