即習:メニューを作ろう!(ResEdit(3)) 2000.Sep. ということで(いささか強引な気もするが)メニュー、作ってみましょう。 必要なリソースはMENUとMBARですね。先ずMENUかな。 最初はApple menu。アバウトダイアログのために1つだけ項目を作る。 次は Fileメニュー。最低でもQuitは付けるべきでしょうね。 大体は感性で操作すればできるんで(できるはず)説明をはしょります。 新しいメニューとか項目を作る時はResourceメニューを開けば大概何とか なるはずです。 メニューアイテム(CutとかPasteとか)を挿入するのは新規に作ったアイテム (一番下にできる)をドラッグして移動させればOK。 ここで注意。アイテムがない所をクリックするとResEditが自爆します。 う〜む。ResEdit、開発終了してるらしいけどこんなバグは直して欲しいぞ。 次にMBAR。さっき作ったMENUのリソースIDを並べるだけ。項目の追加・挿入は 1) *****とかの表示部分をクリックしてResourceメニューを使います。 ちなみにMBARはトップレベルのメニューのみ登録します。サブメニューがある 場合はどーするか。というと。 とりあえずMENUリソースでサブメニューのアイテムを作成。サブメニューの タイトルは無視されるので適当に付ければ良いでしょう。 ここで。Resource->Get Resource InfoにてリソースのIDを変更(200とか) します。 #いや別に変更しなくても一向に構わないのですが、自分が混乱しないように。 という配慮です。 すると何やら文句を言うダイアログが出てきます。リソースIDとメニューIDが 違うけど、一致させるか?です。ややこしいことにメニューには2種類のIDが あるんですね。んで、どっちを使えば良いのか。などとゆー下らないことに気を 使うのは馬鹿げているのでここは素直に一致させる[OK]を選んでおきます。 ちなみにMENU->Edit Menu & MDEF IDってメニューがありますのでご確認を。 で。親メニュー(サブメニューがあるメニューですぞ)のアイテムでhas Submenu にチェック入れればIDを入れるところが出てくるので、サブメニューのID (200とか)を入れる訳ですね。 ResEditでやることはここまで。後はソース。メニューを生成する部分はこんな 感じとなります。 サブメニューは挿入処理をしてやる必要があります。どこに挿入するか (InsertMenu()の引数)は-1を指定すればサブメニューだな。とOSが判断して くれます。 そしてそのサブメニューの親はどこだ。ってのは上に書いたような仕儀で自明 ということです。 #だったらサブメニューも自動的にロードせい!とか思うけど、これは必要な 時にサブメニューをメモリにロードすることで少しでもメモリ使用量を 減らしたい。という親心かな? @仮想メモリやまして64Mや128M程度な物理メモリはあって当然。という昨今の 情勢だと、まぁアレですけど #define rMenu 128 // MBARリソースのID #define mApple 128 // AppleメニューのID #define mSUB 200 // サブメニューのID で、main()の中でこうするんです。 Handle menu; MenuHandle mh; // Create menu menu = GetNewMBar(rMenu); if (menu == nil) return 1; SetMenuBar(menu); DisposeHandle(menu); AppendResMenu(GetMenuHandle(mApple), 'DRVR'); /* いきなり'DRVR'とはどーゆーつもりか?とか思うけど、これで正解なん だからしょうがない(でもこれ、Cの文法ぢゃないよぉ) */ // Adds submenus mh = GetMenu(mSUB); InsertMenu(mh, -1); DrawMenuBar(); さて。メニューはマウスとキーボードで操作できます。とゆーことは それぞれでプログラムが必要。こんな感じ。 // mouse Boolean doMouseDown(EventRecord *event) { WindowPtr win; switch (FindWindow(event->where, &win)){ case inMenuBar: doMenu(MenuSelect(event->where)); break; ... (以下略) // keyboard Boolean doKeyEvents(EventRecord* event) { // menu short cut if (event->modifiers & cmdKey){ if (event->what == keyDown) doMenu(MenuKey(event->message & charCodeMask)); return true; } ... (以下略) で、メニュー自身の処理はとゆーと、こんなんです。 ちなみにアイテムの途中にセパレータバーがあるとメニューアイテム番号は 飛びます。どーゆーこっちゃといえば: ---------------------- ○ File FooBar --------+-----+------- |hoge | |foo | +-----+ |bar | +-----+ とゆーメニューがあった場合、fooのアイテム番号は2で、barは4。という ことです。 #下のソースは上の図とは思いっきり違うメニュー構造を処理しています。 念のため #define mFile 129 // FileメニューのID #define iAbout 1 // Appleメニューの最初のアイテム #define iOpen 1 // Fileメニューの最初のアイテム #define iQuit 2 // Fileメニューの次のアイテム #define kAbout 130 // アバウトダイアログ(アラート)のリソースID void doOpen(WindowPtr win); // メニューに応じて何かするルーチン extern Boolean done; // これがtrueになるとアプリケーション終了 // menu handling void doMenu(int menu) { short mitem; WindowPtr win; Str255 DAnam; // ToDo: enable/disable menu here GetPort(&win); mitem = LoWord(menu); switch (HiWord(menu)){ case mApple: // Appleメニュー switch (mitem){ case iAbout: Alert(kAbout, nil); break; default: GetMenuItemText(GetMenuHandle(mApple), mitem, DAnam); OpenDeskAcc(DAnam); } break; case mFile: // Fileメニュー switch (mitem){ case iOpen: doOpen(win); break; case iQuit: done = true; break; case mSub: // サブメニュー switch (mitem){ ... (中略) } break; } HiliteMenu(0); // 反転しているメニューを元に戻す } (EOF)