arrize.net

プログラミングに関することとかいろいろ。

« Advanced/W-ZERO3[es]買いました。 | メイン

WindowsMobile用アプリ開発メモ(3)

前回のエントリから2ヶ月ほど経ってますが・・・
今回はメニューバー(この画像の下部)の作成です。
通常のWin32アプリケーションの場合と比べるとWindowsMobileではなかなかの曲者です。

では、実装は"続きを読む"からどうぞ。
サンプルプロジェクトはこちら

  1. リソースの作成
    まず表示したいメニューリソースを作ります。ちなみに最上位要素のキャプション等といった属性は無視されます。ソフトキーを押したときに出てくるプルダウンメニューをそれぞれ最上位要素でまとめて作るような具合です。
    このサンプルではサブメニューを持つ要素は右側のみなので最上位要素は一つのみです。以下に示すようなリソースを使用しています。
    IDR_MAINMENU MENU
    BEGIN
        POPUP ""
        BEGIN
            MENUITEM "項目(&2)",                      ID_ELEM002
            MENUITEM SEPARATOR
            MENUITEM "選択不可(&D)",                    ID_ELEM003, GRAYED
            MENUITEM "項目(&3)",                      ID_ELEM004
        END
    END
    次に最上位項目のキャプションとなる文字列を記録したストリングテーブルを作成します。サンプルコードのリソースではそれぞれIDS_MENU1が左側の、IDS_MENU2が右側の要素のキャプションとなっています。
    以下、サンプルコードのストリングテーブル部分です。
    STRINGTABLE
    BEGIN
        IDS_MENU1               "項目1"
        IDS_MENU2               "ポップアップ"
    END
    最後にソフトキーにメニュー項目を対応するための情報を記述するのですが、どうもこれだけはVisual Studioのリソースエディタが利用できないようで.rcファイルを直接編集することになります。ちなみに、この情報を記述した後にVisual Studioのリソースエディタで.rcファイルを編集するとよく分からないデータに変換されてしまいます。サンプルコードのアーカイブの中には変換される前のデータとして"WM003/WM003_Original.rc"というファイルを同梱しているので読むときはこちらを参考にしてください。この部分のサンプルコードは以下の通りです。
    IDR_MAINMENU RCDATA DISCARDABLE
    BEGIN
        IDR_MAINMENU,    // メニューのリソースID
        2,                // トップレベル要素の数

        I_IMAGENONE, ID_ELEM001, TBSTATE_ENABLED,
        TBSTYLE_BUTTON | TBSTYLE_AUTOSIZE,
        IDS_MENU1, 0, NOMENU        // 1つ目の要素

        I_IMAGENONE, 0, TBSTATE_ENABLED,
        TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE,
        IDS_MENU2, 0, 0                // 2つ目の要素
    END
    BEGIN以後の2つの要素はコメントの通り、そしてそれぞれの要素の部分ですが、各要素に対して
    • ボタンに画像を使用するか否か(通常はI_IMAGENONE(画像を使用しない))
    • トップレベル要素がボタン要素(選択するとWM_COMMANDメッセージが発行されるもの)である場合、それが押されたとき発行されるコマンドのID
    • 要素の初期状態(通常はTB_STATE_ENABLED)
    • 要素のスタイル(TBSTYLE_BUTTONを指定すればボタン要素に、TBSTYLE_DROPDOWNを指定すればプルダウンメニューを持つ要素になります。とりあえずはこの2つのいずれかとTBSTYLE_AUTOSIZEの組み合わせがよく使われるものかと思われます。)
    • メニューバーに表示するキャプションを格納したストリングテーブル内要素のID
    • よく分からないけれどもとりあえず0(予約済み領域?)
    • 選択されたときに表示するサブメニューがメニューリソースの何番目の要素であるか(0から開始、ボタン要素の場合はNOMENU)
    を","で区切って順番に並べたものを最上位要素の数だけ記述します。Visual Studioで勝手に入れてくれれば楽でいいんですけどねぇ・・・
    ここまででリソースの準備は完了です。
  2. メニューの生成処理を追加
    リソースの準備が出来たらメニューを追加したいタイミング(おそらく大抵はWM_CREATEやWM_INITDIALOGメッセージが飛んできたとき)にSHCreateMenuBar関数を呼び出します。
    以下はサンプルコードのメニューバー生成部分(WM_CREATEメッセージが発行されたときに実行しています)。
    SHMENUBARINFO mbi;
    memset(&mbi, 0, sizeof(SHMENUBARINFO));
    mbi.cbSize     = sizeof(SHMENUBARINFO);
    mbi.hwndParent = hWnd;
    mbi.nToolBarId = IDR_MAINMENU;
    mbi.hInstRes   = g_hInstance;
    if(SHCreateMenuBar(&mbi) != FALSE){
        RECT rect, rectMB;
        GetWindowRect(hWnd, &rect);
        GetWindowRect(mbi.hwndMB, &rectMB);
        int cy = IsWindowVisible(mbi.hwndMB) ? rectMB.top - rect.top : rectMB.bottom - rect.top;
        SetWindowPos(hWnd, NULL, 0, 0, rect.right - rect.left, cy, SWP_NOZORDER | SWP_NOMOVE);
    }else{
        MessageBox(hWnd, TEXT("SHCreateMenuBar Failed"), TEXT("Error"), MB_OK);
    }
    SHCreateMenuBar関数に渡すSHMENUBARINFO構造体へはまずゼロクリアした後にcbSizeに構造体のサイズを、hwndParentにメニューを持たせるウィンドウのハンドルを、nToolBarIdにメニューとして設定したいリソースのIDを、hInstResにはリソースを含むインスタンスのハンドルをそれぞれ記録します。その他の項目についてはMSDNライブラリのSHMENUBARINFOの項(リンク先は英語)を参照してください。
    そして、メニューバーの生成が成功したらウィンドウの下にメニューバーを表示する領域が出来るようにウィンドウをリサイズします(おそらくメニューバーはウィンドウの下端にくっつくような配置をされるのでしょう)。
さて、長々と書きましたがこれでメニューバーの表示が出来たかと思います。いかんせん説明が足りないところもあるかと思うので最後に参考リンクを。

トラックバック

このエントリーのトラックバックURL:
http://arrize.net/mt/mt-tb.cgi/8

コメントを投稿