vieweditattachhistorytopchangessearchhelp

第57回


■SqueakではじめるSmalltalk入門   第57回


本連載では、名前は知っていてもなかなか触れる機会のないSmalltalkについて、最近話題のSqueakシステムを使って紹介しています。前回はサブモーフやサブモーフ化という仕組みを取り上げました。そこで、このサブモーフ化という仕組みをふまえて、いま一度、ポップアップメニューやウインドウがどのような構成になっているかを調べてみましょう。まずはポップアップメニューから。

ポップアップメニュー(メニューモーフ)は、たとえば、次のようなスクリプトで簡単に記述することができます。

| menu |
menu := MenuMorph new.
menu defaultTarget: 1.
menu add: 'default (one)' action: #inspect.
menu addLine.
menu add: 'two'   target: 2 selector: #inspect.
menu add: 'three' target: 3 selector: #inspect.
menu add: 'four'  target: 4 selector: #inspect.
menu addLine.
menu
  add: 'open workspace'
  target: Workspace
  selector: #openLabel:
  argument: 'My New Workspace'.
menu invokeModal


このスクリプト全体を選択しdo it(cmd + D)すると、その場に次の図に示すようなメニューが現れます。

[fig.A]スクリプトで作られたポップアップメニュー
Uploaded Image: 57a.png

もちろん格好だけではなく、メニューとしてきちんと機能します。「default (one)」を選択すると「1」のインスペクタが、「two」「three」「four」ではそれぞれ「2」「3」「4」のインスペクタが表示されます。最後の「open workspace」では「My New Workspace」というタイトルの付いた新しいワークスペースが現れます。

ポップアップメニューのモーフとしての“姿”と“振る舞い”を確認できたところで、今度は先ほどのSmalltalkで記述されたスクリプトの中身を読み下してみましょう。

このスクリプトでは最初で、テンポラリ変数「menu」にa MenuMorph(MenuMorphのインスタンス)を束縛しています。MenuMorphは、その名の示すとおり、メニューの役割を果たすモーフの属するクラスです。

このmenu(に束縛されているa MenuMorph)にメニュー項目(a MenuItemMorph)や区切り線(a MenuLineMorph)をサブモーフ化することでメニューは構成されています。ですが、いちいちメニュー項目や区切り線の細かな仕様を決めてサブモーフ化するのは大変なので、#add:action:(あるいは、#add:target:selector:、#add:target:selector:argument:)や、#addLineという便利メソッドを起動するメッセージを最低限のパラメータを添えて送信することで、そのような面倒な“手続き”に代えています。

たとえば、メッセージ「addMenu」で起動する「MenuMorph >> #addLine」メソッドの定義は、次のようになっています(スクリプト中の「addLine」部分を選択して、browse it(cmd + B)で呼び出せます)。

MenuMorph >> addLine
  submorphs isEmpty ifTrue: [^ self].
  (self lastSubmorph isKindOf: MenuLineMorph)
     ifFalse: [self addMorphBack: MenuLineMorph new]


ここで「submorph」は、すべてのモーフが持つインスタンス変数で、そのモーフに登録されたサブモーフたちを収めた配列を束縛しています。したがってこのメソッドには、「項目が何もないメニュー、あるいは、最後のサブモーフが区切り線の場合は手を付けず、それ以外なら、区切り線をサブモーフとして追加する」という内容が記述されていることを読み取ることができるでしょう。どうです(#addMorph:こそ起動していませんが)ちゃんとサブモーフ化の手続きがとられていますね。メソッド(#add:target:selector:argumentList:)をひとつ介しますが、メニュー項目(#add:action:)についてもしかりです。

メニュー項目(a MenuItemMorph)を追加するメソッドはいくつかありますが、最低限、メニュー項目に付けるラベル(文字列)と、その項目を選択されたときに送るメッセージのセレクタ(シンボル)を引数として渡してあげる必要があります(#add:action:)。ターゲットを指定しない場合は、メニューが把握しているデフォルトのターゲットに指定したセレクタを含むメッセージが送信されます。デフォルトターゲットは初期状態ではnilですが、メニューに「defaultTaget: ...」を送信することで変更可能です。

今回作成したメニューでは、デフォルトターゲットに「1」を指定しています(defaultTarget: 1)ので、ターゲットを明示的にせずにサブモーフ化されたメニュー項目「default (one)」では、その選択時にメッセージ「inspect」が「1」に送信されます。結果、「1」のインスペクタが現れる…というカラクリです。実際のアプリケーションでは、このメニュー選択をトリガーにして行ないたい事柄を体現するメッセージを、それにふさわしいオブジェクト(ターゲット。たいていはアプリケーションのモデル)に送るよう指示しておけばよいことになります。

ターゲットはメニュー項目ごとに変えることもできます。それが「two」から「four」までの例です。それぞれ、第二パラメータ(第二引数)に希望するターゲット(「2」か「3」か「4」)を添えて、#add:target:selector:というメソッドを起動するメッセージをmenuに送信しています。

ターゲットに送信するメッセージにパラメータが必要な場合は、#add:target:selector:argument:を起動するメッセージを送ります。最後の「open workspace」がその例です。新しいワークスペースを開きたいときには、Workspaceに「openLabel: titleString」というメッセージを送るのですが、メッセージ「inspect」と異なり、この際、ウインドウタイトルを明示的にするためのパラメータ(例では'My New Workspace')が必要になります。menuへのメッセージ送信時にはこれを第三パラメータとして添えています。さらに多く(2つ以上)のパラメータが必要なメソッドを起動したいとき向けには、「add: itemString target: targetObject selector: selectorargumentList: argArray」というメッセージも用意されています。


次回は、このメニューをモーフとしてバラバラに分解してみて、メニュー項目モーフの中身がスクリプトでの注文通りの仕様になっているのかを確認してみましょう。

このページを編集 (5151 bytes)


Congratulations! 以下の 1 ページから参照されています。

This page has been visited 750 times.