メニューの作り方2

メニューリソースというのは、メニューそのものではなくて、メニューをつくるときの項目のテキストとか、項目数、あるいはショートカットキーとかチェックマークとか、そういった事柄をどうするかに関するデータを保管しているに過ぎません。逆に言えば、メニューをつくる時点でそういったデータを補ってやれば、リソースなしでもメニューはできるわけです。そのかわり、少し面倒ですが。

まず、メニューオブジェクトを宣言で生成するのは、リソースベースのメニューと変わりはありません。例えば、4項目のメニューとして、
4 menu myMenu
ここで、普通はコンパイルタイム初期化をするわけですが、リソース抜きでメニューを生成する関数の仕様のために、今の場合は初期化はメニューの生成後、ランタイムにする必要があります。そこで、次にするのは、メニューを生成するワードの作成です。Mops環境上でならインタープリターでメニューを生成できますが、アプリケーションとして書く場合を考えてワード定義としてコンパイルして行きましょう。

非リソースベースメニューを生成するメソッドは、"new:"です。
: CreateMyMenu   " File" new: myMenu  ;
引数としてメニュータイトルの文字列(addr len)をとります。このメソッドは、このタイトルで、項目が一つもないメニューを生成します。ですから、次に、項目を生成しなければなりません。項目生成はその項目の名前(表示する文字列)と一緒に上から追加していきます。
: CreateItems
 " Open" addItem: myMenu
 " Save" addItem: myMenu
 "  " addItem: myMenu
 " Quit" addItem: myMenu   ;
ちょっとClassic風ですが、まあ、いいですよね。三番目は、半角空白文字を一つだけ入れています。これは仕切り線にしようとしているわけです。ちなみに、PowerMops 5.6からはCFStringを経由してメニュー項目名をつけているので、文字化けした日本語文字列でも、メニューにはちゃんと日本語で表示されるはずです。
すみません、勘違いでした。AddItem:だけは、日本語は化けたままです。日本語にしたいときは、"putItem: ( item# addr len -- )"で文字列を取り替えてください。これと関連して、空っぽの文字列を名前にするとメニュー項目が生成されないようなので、名前として取りあえず最低限、半角空白一つは入れておく必要があるようです。

さて、項目が生成されたので、メニューの動作を決めるワードを登録することができるようになりました。ここで、Initをするわけです。
: InitializemyMenu   xts{ word0 word1 null word3 } 128 init: myMenu  ;
趣旨はリソースベースのメニューと同じです。128はリソースID風ですが、そうではなくて、単なるメニューIDです。

最後にお化粧として、第三項目を区切り線に変えます。なんか、一時期OS Xでは区切り線というものがなかったらしいですね。OS 9からPantherに飛んだのでよくわからないんですが。PantherにはOS9との連続性が結構あって、良かったです。Tigerにも期待してます。それはともかく、第三項目を区切り線にかえるには、次のメッセージを送ります。
: SepLine   2 separateLine: myMenu  ;
このメソッドはPowerMops 5.6で追加されたものです。Mopsのメニューオブジェクトでは、項目の数え方が0ベース、つまり、0から始まっていることに注意しましょう。なので、第三項目のアイテム番号は2になります。

これで、生成部分は全部できたので、後は表示するだけです。これまでのをまとめて、
: GetmyMenu
 CreatemyMenu
 CreateItems
 InitializemyMenu
 SepLine
 insert: myMenu
;
となります。まあ、こんな風にワードを小分けする必要は全くありません。全部一つのワードにぶち込んでも、長過ぎてわけが分からんということもないんじゃないでしょうか。まあ、どうなるかやってみると、
: GetmyMenu
 " File" new: myMenu
 " Open" addItem: myMenu
 " Save" addItem: myMenu
 "  " addItem: myMenu
 " Quit" addItem: myMenu 
 xts{ word0 word1 null word3 } 128 init: myMenu
 2 separateLine: myMenu
 insert: myMenu
 ;
ですね。PowerMops 5.6からの新機能であるCascadingを使えば、
: GetmyMenu
 " File" new: myMenu
 " Open" addItem: |
 " Save" addItem: |
 "  " addItem: |
 " Quit" addItem: | 
 xts{ word0 word1 null word3 } 128 init: |
 2 separateLine: |
 insert: |
 ;
となります。書く人にとってはかなり楽です。

コマンド+文字のショートカットキーを設定したいときには、"setCommandKey:"メッセージを送ります。
: SetCommandKeys
 0 & O setCommandKey: myMenu
 1 & S setCommandKey: myMenu
 3 & Q setCommandKey: myMenu   ;

なお、リソースなしでメニューをつくるなら、"setCommandKey:"なしでもコマンドキーを設定できます。"addItem:"のときに、アイテムの文字列にスラッシュ+文字を混ぜればいいだけです。例えば、
" Open/O" addItem: myMenu
のようにすれば、0 & O setCommandKey: myMenuは必要ありません。

これは、"addItem:"で該当アイテムの追加が終わった後ならいつでも実行できます。"&"は、次の1文字をアスキーコードの数値に変換するワードですが、Mops固有ワードとなっています。Forth標準では、同じ目的のためには、ワード定義内(コンパイル状態)では"[char]"、その外(インタープリト状態)では"char"と使い分けることになっています。

なお、キーの大文字小文字についてですが、この登録のときに大文字[小文字]を使うと、メニュー上の表示ではそれが反映されて大文字[小文字]で表記されますが、実際のショートカットキーの動作は、どっちでも同じなようです。

この登録も一つのワードに込めてしまうと、結構定義が長いですかね。自分なら気にせず混ぜちゃいますけどね。途中を区切ってコメントしたりはしますが。まあ、こういうことを気にするのはForth系だけなんでしょうけど。


関連項目:






最終更新:2018年12月28日 19:30