はじめてのMorphicチュートリアル(第10回)「キーボードイベント」

今回はモーフでキーボードイベントを受け取る方法について学ぶ。
まず、テキスト入力などで用いるようなキー入力を処理する方法について説明する。
キーボードイベントは、keyStroke:メッセージの引数としてモーフが受け取る。受け取ったキーボードイベントに対して、keyCharやkeyString、keyValueのメッセージを送ることで、文字や文字列、文字コードを得ることができる。
例えば、受け取った文字を画面に表示したい場合には以下のようにkeyStroke:メソッドを実装する。また、マウスイベントの時と同様、handlesKeyStroke:メソッドがtrueを返して、キーボードイベントを受け取れるようにする必要がある。

keyStroke: anEvent
    self inform: anEvent keyString
handlesKeyStroke: anEvent
    ^ true

加えて、イベントを受け取るモーフがキーボードフォーカスを取得しなければならない。
Morphicでは、ActiveHandモーフがキーボードフォーカスを管理しているので、

ActiveHand keyboardFocus: モーフ

のように明示的にモーフにキーボードフォーカスを移す必要がある。
整理するとキーボードイベントを処理するには、以下の3つが必要である。

  • キーボードフォーカスを取得する
  • handlesKeyStroke:メソッドを実装してtrueを返す
  • keyStroke:メソッドを実装して、キーボードイベントを受け取る

keyDown:メッセージとkeyUp:メッセージを用いると、キーボードを押したのと離したのを区別してイベントを受け取ることができる。この場合もこれまでと同様に、handlesKeyDown:メソッドとhandlesKeyUp:メソッドをそれぞれ実装するか、これらのイベントをまとめて受け取れるようにするhandlesKeyboard:メソッドを実装する。
今回は実際に試せる例を紹介しなかった。近いうちにキーボードイベントを処理する例を紹介しようと思う。
(第10回おわり)

はじめてのMorphicチュートリアル(第9回)「マウスイベント」

モーフはそれぞれが個別にマウスイベントやキーボードイベントを受け取ることができる。
今回は、第7回までで紹介したMyMorphでマウスイベントを受け取る方法について学ぶ。
受け取ることのできるマウスイベントは以下の通りである。

  • マウスボタンを押した
  • マウスボタンを離した
  • マウスボタンを押したままマウスカーソルを動かした
  • マウスボタンを押したままである
  • マウスカーソルが領域に入ってきた
  • マウスカーソルが領域から出た

まず、マウスボタンを押した/離したのイベントを受け取る方法について説明する。この2つのイベントを受け取るには、少なくとも2つのメソッドを定義する必要がある。

handlesMouseDown: anEvent
    ^ true

上記のように、handlesMouseDown:メソッドをMyMorphに加えてtrueを返すようにすると、MyMorphの上でマウスボタンを押した時にmouseDown:メッセージが、離した時にmouseUp:メッセージがそれぞれ送られてくる。
ところで、true/falseは真理値と呼ばれYes/Noのような状態を表す。もし、上のメソッドでtrueをfalseで置き換えたらmouseDown:メッセージは送られてこなくなる。
試しに、mouseDown:とmouseUp:をそれぞれ以下のように定義してみよう。

mouseDown: anEvent
    self extent: self extent + (10@10)
mouseUp: anEvent
    self extent: self extent - (10@10)

いつものようにPlaygroundから、MyMorph new openInWorldでMyMorphを生成すると色を変えながら移動するMyMorphが現れる。モーフにマウスを会わせてクリックすると、押している間だけ大きくなり離すと小さくなる。
次にマウスボタンを押し続けた時にイベントを受け取る方法について、ドラッグ動作であれば以下のメソッドを追加すればよい。

mouseMove: anEvent
    self center: anEvent cursorPoint

上の例ならば、MyMorphを掴んで動かすとマウスポインタにあわせてMyMorphも移動するようになる。
マウスボタンを押しっぱなしにした時にイベントを受け取るには、handlesMouseStillDown:メソッドとmouseStillDown:メソッドを実装する。

handlesMouseStillDown: anEvent
    ^ true

handlesMouseStillDown:はhandlesMouseDown:と同様である。trueの前にハット(^)が書かれているのは、このメソッドがメッセージの送り主に対して、その後に続く値(この場合はtrue)を返すことを表している。実際にはどのメッセージも値を返しており、明示しない場合は送り先のオブジェクト自身(この場合はMyMorph)が返されている。

mouseStillDown: evt
    self delete

以前にも述べたように、deleteメッセージを送れば任意のモーフを消すことができる。当然、自分自身にdeleteメッセージを送れば、自分を消すことができる。
長押しの時間を設定するには、mouseStillDownThresholdメソッドを定義して、ミリ秒単位の数値を返す。

mouseStillDownThreshold
    ^ 1000

この例では、長押しでモーフが削除されるようになる。
マウスカーソルがモーフの領域内に入った/出た場合にイベントを受け取るには、handlesMouseOver:メソッドとmouseEnter:メソッド、mouseLeave:メソッドを実装する。

handlesMouseOver: anEvent
    ^ true

handlesMouseDown:やhandlesMouseStillDown:メソッドと同様に、trueを返すことでイベントが送られるようになる。

mouseEnter: anEvent
    self borderColor: Color black.
    self borderWidth: 1

マウスがモーフの領域内に入ると黒い枠線が表示されるようにした。

mouseLeave: anEvent
    self borderWidth: 0

マウスが領域外に出ると枠線が消される。
以上のような形でマウスイベントを取り扱う。
(第9回おわり)

はじめてのMorphicチュートリアル(第8回)「サブモーフ」

今回はMorphicの大きな特徴ともいえるサブモーフについて学ぶ。
サブモーフとは、モーフの中に別のモーフを埋め込むことで、これにより様々なモーフを関連づけてリッチな表現を生み出すことが可能になる。
ここでは2つのモーフa,bを例にとって説明する。
モーフaは青色で横200px、縦100pxの長方形のモーフ、モーフbは赤色で縦横20pxの正方形のモーフとすると、以下のようなコードで表現できる。

a := Morph new color: Color blue; extent: 200@100.
b := Morph new color: Color red; extent: 20@20.

以下のコードで、この2つのモーフを画面に表示する。

a openInWorld.
b openInWorld.

two morphs
この2つのモーフをクリックするとマウスにくっついて動くが、それぞれは独立していて互いに何の関連もない。
この状態で以下のコードをDo itする。

コードを選択して右クリック後にDo itを選ぶことを、今後は単に「Do itする」と表現する。メニューから選ぶ代わりにCommand-D(Alt-D)を押しても同じである。

a addMorphBack: b.

上記のようにすると青色の長方形モーフaと赤色の正方形モーフbが一緒に動くようになる。これは、モーフaにモーフbが埋め込まれた状態で、いわばモーフaとモーフbが親子関係になったと言える。このとき、モーフbをモーフaのサブモーフと呼ぶ。
興味深いのは、コードをDo itした時点で埋め込まれたモーフbと外側のモーフaとに、レイアウト上何の変化も生じず、それまでの位置状態を保ったままだったことである。Morphicでは特に指定しない限りレイアウトのない状態となっている。
モーフbがモーフaのサブモーフである状態で、モーフbの位置を変えることができる。

b center: a center.

上記のコードはモーフbの中心を、モーフaの中心にあわせる。この後でモーフaを移動させると、モーフbはモーフaの中心に位置したまま一緒に移動する。
centered morph
今度はモーフaの位置を変えてみる。

a topLeft: 20@20.

上記のコードは、左上端が(20,20)という座標になるようにモーフaを移動する。この場合もモーフbはモーフaの中心に位置したまま一緒に移動する。
サブモーフになったモーフは親のモーフと一心同体となる。つまり、親のモーフを削除するとそのサブモーフも自動的に削除される。
モーフは他のモーフを何個でもサブモーフにすることができる。さらにサブモーフも別のモーフをサブモーフにすることができる。
ただし、サイクリックなサブモーフ化はできない。例えば以下のコードをDo itすると(しないほうがいいが)一瞬でハングする。

b addMorphBack: a. "注意:Do itするとハングする"

モーフ側で何のチェックも行われないので、サイクリックなサブモーフ化には気をつけるほうがいいだろう。
(第8回おわり)
【追記】
サブモーフの配置はMorphicで最も頭を悩ませるものの一つである。これに関しては以前にまとめた記事があるので参照してほしい。
Morphの設定

はじめてのMorphicチュートリアル(第7回)「stepping」

今回は、前回作成したMyMorphを使って簡単なアニメーションを作成する。
Morphicではアニメーションを実現する仕組みとしてsteppingが用意されている。
steppingとは、一定の時間間隔でモーフにstepメッセージが送られるという簡単な仕組みのことである。
メインの動作とは別に、モニタした値を定期的に表示することなどが、新たなスレッドを使わずに実現できる。
stepというメソッドを実装すればsteppingを始めることができる。

step
    self color: Color random

第5回で説明したように、System BrowserでMyMorphを表示させ、initializeと同じ方法で上のstepメソッドをMyMorphに追加する。
Pharo2.0以降ならば、Acceptした瞬間からMyMorphの色がランダムに変わっていくのを観察することができる。
古いPharoやSqueakならば以下のメソッドを追加する必要があるかもしれない。

wantsSteps
    ^ true

デスクトップ全体を表すモーフであるWorldMorphの描画サイクルの一部として、stepメッセージが送られてくるため、モーフ側ではstepを実装する以外に設定する必要がない。
デフォルトでは1000ミリ秒間隔でstepメッセージが送られてくるが、その間隔はstepTimeメソッドにミリ秒単位で設定できる。

stepTime
    ^ 500

上のメソッドをMyMorphに登録すると、stepメッセージが500ミリ秒ごとに送られるようになる。
それでは、steppingを使ってモーフを動かしてみよう。
第3回で説明したモーフの位置設定の方法を利用して、先ほどのstepの定義を以下のように変更してみる。

step
    self color: Color random.
    self topLeft: (self topLeft + (2@0))

すると、Acceptした瞬間からゆっくりとMyMorphが右に移動していくのがわかる。MyMorphは500ミリ秒ごとに色を変えながら、右に2ピクセル移動している。
Playgroundから適当な間隔を置いて以下の式をDo itすると、Command-D(Alt-D)を押すと複数のMyMorphが色を変えながら移動していく。

MyMorph new openInWorld.

モーフは画面外に出てしまっても動き続けるので、MyMorphの全てを一度に削除する方法を教えよう。

MyMorph allInstances do: [ :each | each delete ].

モーフに対してdeleteメッセージを送れば、画面から消すことができる。

(第7回おわり)

はじめてのMorphicチュートリアル(第6回)「initializeメソッド」

前回MyMorphに追加したinitializeメソッドを見てみよう。

initialize
    super initialize.
    self extent: 16@16

1行目は何のメソッドの定義なのか示しており、この場合は追加したい単項メッセージのinitializeを書いている。
2行目はsuper initializeとなっている。第4回で説明したように、モーフとしての性質をMorphから受け継ぐために、MyMorphの親クラスをMorphに設定している。initializeメッセージを受け取ったときにモーフとして行うことは、Morphクラスのinitializeが定義しているので、super initializeというメッセージを送って利用している。このように、MyMorphの親クラス(この場合Morph)で定義されたメソッドを使う場合にはsuperに対してメッセージを送るようにする。
3行目は、第2回で学んだモーフの大きさを変えるメッセージ extent: を用いて、モーフの大きさを16×16ピクセルにしている。
以上、メソッド本体の2行によって、モーフの初期化を完了させつつ大きさを設定していることがわかる。
続いてモーフの色も変えてみよう。モーフの色は、colorメッセージを用いて取得し、色を引数としてcolor:メッセージを送ることで設定できる。

Morph new color. "Color blue"

MyMorphの色を赤に変えたければ、initializeメソッドを以下のように変更すればよい。

initialize
    super initialize.
    self extent: 16@16.
    self color: Color red

今まで明示的には述べてこなかったが、モーフ(や他のオブジェクトに)メッセージを送る式をメッセージ式と呼ぶ。例えば、super initializeやself extent: 16@16などがメッセージ式にあたる。複数のメッセージ式は、ピリオド(.)によって区切る必要がある。最後のメッセージ式についてはピリオドを省略しても良いため、上のself color: Color redの後にはピリオドがない。
なお、1行目のメッセージの定義部分や、後で紹介する値を返却する部分などにはピリオドを付けてはいけない。
PlaygroundでいつものようにMyMorphを生成すれば、画面上に小さな赤い正方形が現れるだろう。

MyMorph new openInWorld.

blueやredのように、Colorクラスに送って作りだせる色の種類は以下のようにして知ることができる。

Color class selectorsInProtocol: 'defaults'.

上記を選んでCommand-P(Alt-P)を押すと、コメントアウトされたメッセージ名が表示される。
"#(#black #blue #brown #cyan #darkGray #defaultColors #defaultColors2 #defaultColors3 #defaultColors4 #gray #green #lightBlue #lightBrown #lightCyan #lightGray #lightGreen #lightMagenta #lightOrange #lightRed #lightYellow #magenta #orange #paleBlue #paleBuff #paleGreen #paleMagenta #paleOrange #palePeach #paleRed #paleTan #paleYellow #pink #purple #red #tan #transparent #veryDarkGray #veryLightGray #veryPaleRed #veryVeryDarkGray #veryVeryLightGray #white #yellow)"
蛇足だが、固定的な色ではなく毎回異なる色にしたい場合には、Color randomを用いる。

initialize
    super initialize.
    self extent: 16@16.
    self color: Color random

こうすると、MyMorphを生成するたびにいろんな色で正方形が表示される。
(第6回おわり)

はじめてのMorphicチュートリアル(第5回)「メソッドの登録」

前回はモーフを拡張したMyMorphクラスを作成した。実際には何も機能は追加せず設定も変えなかったため、元のモーフと(見た目は)全く同じである。
今回はMyMorphに変更を加え、元のモーフとは異なる大きさに変化させる。
Morphを生成すると、幅が50ピクセル、高さが40ピクセルの青で塗りつぶされた長方形が表示される。これを縦横16ピクセルの正方形に変えよう。
第2回のように、生成したモーフに後から設定を行って大きさを変えることは可能だが、モーフを生成した時点からそのような大きさにする場合、初期化のプロセスを修正する必要がある。モーフ(に限らずどのオブジェクトも)は生成の途中で、自分に対してinitializeメッセージを送る。(Behaviorクラスのnewで定義されている)
そのため、初期化を担うinitializeメソッドに修正を加えたいのだがモーフ全体が変わってしまうと困るので、MyMorphに新たにinitializeメソッドを追加して対応する。
initializeメソッドを追加するには、ワールドメニューからSystem Browserを起動する。System Browserで前回のMyMorphクラスを探すのだが、手っ取り早く見つけるために左上の小さな入力欄にクラスカテゴリの一部を入力する。
設定したクラスカテゴリは’Hajimeteno Morphic Tutorial’だったので、入力欄に haji と入力するとそのクラスカテゴリが現れる。クラスカテゴリ一覧から’Hajimeteno Morphic Tutorial’を選ぶと、上段の左から2番目のペインにMyMorphが現れる。これは、選んだクラスカテゴリに属するクラスの一覧である。クラスペインからMyMorphを選ぶと、その右のペインにno messagesが現れる。上段の右から2番目のペインには、選択したクラスのプロトコルの一覧が現れる。プロトコルとは、これから説明するメソッドの分類を表したものである。ここまでの操作を行い、プロトコルペインでno messagesを選ぶと以下のような画面が表示される。
MyMorphクラス
コードペインには以下のようなテキストが選択された状態になっている。

messageSelectorAndArgumentNames
    "comment stating purpose of message"
    | temporary variable names |
    statements

これはメソッドのテンプレートである。メソッドとはオブジェクトがメッセージを受け取った際、オブジェクトがどんな動作を行うかを定義したものである。メソッドは、オブジェクトが属するクラスに登録することで定義する。上のテンプレートが登録の形式を示している。
1行目は受け取るメッセージを記述する。
2行目にはメソッドのコメントを記述する。コメントの記述は省略することができる。なお、Smalltalkではコメントの両端をダブルクオーテーション(”)で囲む。
3行目にはメソッド内で使用する一時変数を記述する。Smalltalkではメソッド内で利用する一時変数は必ず宣言しておく必要がある。複数の一時変数はスペースで区切り、全体をバーティカルバー(|)で囲む。一時変数を使用しない場合は、2本のバーティカルバーだけを残すこともできるし、それ自体の記述を省略することもできる。
4行目以降にメソッドの内容を記述していくことになる。メソッドの内容を省略することも可能で、その場合はメッセージを受け取っても何もしないことになる。
Smalltalkでは、3種類のメッセージの形式があるのだが、ここでは単項メッセージとよばれる形式のメソッドの書き方だけを学ぼう。先ほど作成しようとしたinitializeメッセージが単項メッセージにあたり、オブジェクトに最も単純なメッセージを送ることができる。先ほどのメソッドテンプレートを書き換えて、以下のように入力する。

initialize
    super initialize.
    self extent: 16@16

入力が完了した時点で赤く表示される部分があれば何か問題があるので入力内容をチェックする。問題なさそうであれば、右クリックでAcceptを選ぶか、Command-S(Alt-S)を押す。すると以下のような画面が現れる。
署名ダイアログ
これはコードを登録した人を記録するためのダイアログウィンドウである。適当な名前やイニシャルを入力してOKを押すと、次回からは表示されなくなる。
さて、メソッドを追加したMyMorphを試したいのだが、今の時点でたくさんの青い四角が画面に溢れているだろう。これらのモーフを削除するには、ShiftとOptionを押した状態でモーフをクリックする。モーフの周囲にたくさんのボタン(Haloと呼ばれる)が現れたら×印のボタンを押してモーフを削除する。
Halo
画面が奇麗になったところで、Playgroundを使って以下のように入力する。

MyMorph new openInWorld.

画面の左上に小さなモーフが表示されるのがわかるだろう。
今回は長くなったのでここまでとし、次回は登録したメソッドの内容について学び、更に追加を行う。
(第5回おわり)

はじめてのMorphicチュートリアル(第4回)「クラス定義」

ここまでモーフの状態を取得したり、設定を行う方法について学んできた。今回は基本的なモーフを拡張して、新たな機能を持ったモーフの作り方について学ぶ。
モーフを拡張して新たなモーフを作るには、Morphクラスのサブクラスを作る必要がある。
そのために、デスクトップをクリックしてワールドメニューを出してSystem Browserを選ぶ。
System Browser
System Browser(システムブラウザ)は、古くからあるSmalltalk上の開発ツールの一つで、コードを作成する場合はたいていこれを使う。5つの大きなペインを持ち、その他にも入力欄やボタンなどが配置されている。これらは重要な機能を持っているので少しずつ紹介していく。
下側の一番大きなペインをコードペインと呼ぶ。ここには、こんな内容が表示されているはずだ。

Object subclass: #NameOfSubclass
	instanceVariableNames: ''
	classVariableNames: ''
	category: ''

これは新たなクラスを生成する際のテンプレートである。新しいクラスを作りたいなら、このテンプレートを修正して使うことができる。新しいモーフを作るために、上の内容を以下のように書き換える。

Morph subclass: #MyMorph
	instanceVariableNames: ''
	classVariableNames: ''
	category: 'Hajimeteno Morphic Tutorial'

書き換えたのは3カ所で、1カ所目は Object を Morph に変えた。Morphを新しく作成するクラスの親(基底)クラスとして、新たなクラスがMorphの性質を受け継ぐようにする。
2カ所目は #NameOfSubclass を #MyMorph に変えた。これは新たなクラスの名前(MyMorph)を表している。名前の前に#(シャープ)記号が付けられているのは、この文字列がSymbol(シンボル)であることを表している。Symbolとは環境内で唯一性を持つ文字列のことである。クラス名は環境内で一意に決まるので命名にはSymbolを用いる。
最後は、category:の後の ” を ‘Hajimeteno Morphic Tutorial’ に変えた。Smalltalkではカテゴリを用いてコードを管理する。カテゴリにはクラスカテゴリとメソッドカテゴリ(プロトコル)があり、ここで指定するのはクラスカテゴリである。後から参照しやすいようなカテゴリ名を付けておく。
ところでSmalltalkでは両端をシングルクオート(’)で囲むことで文字列を表す。だから、 ” は空の文字列ということになる。
クラスを実際に定義するには、入力したコードペインで右クリックして Accept を選ぶかCommand-S(Alt-S)を押す。すると、System Browserの左上のペインが変化して Hajimeteno Morph Tutorial という項目が現れる。
このペインはクラスカテゴリペインと呼ばれ、さまざまに分類されたクラスカテゴリの一覧が表示される。
ワールドメニューでPlaygroundを開き、左側のペインで以下を入力する。

MyMorph new openInWorld.

すると、今までと同じモーフが画面左上に表示されるのがわかる。
さて、今まではMorphにnewというメッセージを送っていた。これは、Morphクラスに属する新しいモーフを生成することを意味している。
今回、MyMorphにnewメッセージを送ることで、MyMorphクラスに属する新しいモーフを生成することになる。
このようにSmalltalkでは、定義したクラスにnewというメッセージを送ることで新たなモーフを生成する。生成されたモーフを定義したクラスのインスタンスとも呼ぶので覚えておこう。
次回、このクラスを拡張する。
(第4回おわり)

はじめてのMorphicチュートリアル(第3回)「モーフの位置」

第2回ではモーフの大きさの取得や設定の方法について学んだ。今回はモーフの位置などを取得・設定する方法について学ぶ。
モーフの位置の取得・設定はさまざまな手段が用意されている。まずモーフの四隅の座標値は以下のメッセージで取得することができる。

topLeft
左上の座標
topRight
右上の座標
bottomLeft
左下の座標
bottomRight
右下の座標

前回の例と同様、上のメッセージにコロン(:)をつけて座標値とともにキーワードメッセージを送ると、それぞれの値を設定することができる。当然のことながら、どのやり方で座標値を設定してもモーフの位置が変化するだけで大きさが変わるわけではない。
取得と設定の応用として、二つを組み合わせた例を以下に示す。これをPlaygroundの右下のペインに入力し、Command-D(Alt-D)で評価してみよう。

self topLeft: (self topLeft + (2@0))

モーフが少し右に移動したのがわかるだろうか。
この式の意味は、まずself topLeftによってモーフの左上の座標値を得る。おそらく最初はモーフ自体が画面の左上にあるため、得られる座標値は0@0となる。
(たいていのコンピューターグラフィックスシステム同様、Morphicでも画面左上が原点(0,0)となっている)
この座標値に対して、2@0という座標値を加える。座標値同士の加減算ではx成分・y成分それぞれについて計算が行われ、新たな座標値が生成される。この場合、(0+2)@(0+0)のような計算によって、2@0という座標値が得られる。
得られた2@0という座標値が、topLeft:というキーワードメッセージによってモーフに伝えられ、モーフの位置が元あった場所から右に2ピクセルほど変化する。これを連続的に用いればアニメーションのような効果が得られるので、後の回でゲームを作るのに利用するつもりである。
さて、座標値の計算式を書く上で間違えやすいのは、以下のように書いてしまうことである。

0@0 + 2@0

Smalltalkにおける@は、+や-と同様の中置演算子である。また、Smalltalkでは同じ種類の演算子において結合の優先順位は定められておらず、単に左から結合されていく。
つまり、上の式は以下のように解釈される。

((0 @ 0) + 2) @ 0

この場合、0@0という座標値に2が加えられる。座標値と普通の数値が加減算される場合、x成分・y成分それぞれに対して数値が加減算されるので、その答えは 2@2 となる。
さらに (2@2) @ 0 という計算が行われるにあたって、「座標値は@というメッセージを知らない」といったエラーが発生する。
MessageNotUnderstood
Smalltalkで実行時エラーが起こると、上のようなNotifier(ノーティファイア)が現れる。エラーについてはいずれ詳しく説明をするが、Notifierを見ると最上段にPoint(Object)とdoesNotUnderstand:が現れている。Notifierで最上段に表示されたものが、このNotifierを表示させている場所であり、この場合ObjectクラスのdoesNotUnderstand:メッセージとなっている。発生したエラーの具体的な意味は、座標値を表すPointクラスから上位のObjectクラスに至るまで、指定されたメッセージ(この場合は@)が見つからなかったということである。
話はどんどん脱線するが、先ほどの間違った式で発生するのはコンパイル時ではなく実行時だということに注意してほしい。つまり、式としては正しい形を成しているのだが、結果的に意味を持たないため実行時にエラーが発生する。Smalltalkはシンプルな文法と柔軟な仕組みで動作しているので、(慣れれば慣れるほど)コンパイル時エラーを出すのは他の言語ほど容易ではない。いずれ、そういったこともチュートリアルの中で説明しよう。
(第3回おわり)

はじめてのMorphicチュートリアル(第2回)「モーフの大きさ」

第1回ではモーフを生成する方法について学んだ。今回はモーフの属性の取得や変更について学ぶ。
Playgroundで以下を入力し緑色のボタンを押すと画面の左上に青色のモーフが現れる。

Morph new openInWorld.

モーフ
モーフの属性を取得したり変更するために、モーフに対してメッセージを送る。
モーフの大きさを取得したい場合には、extentメッセージを送る。Playgroundの右下のペインにselfとだけ表示されている。ここで以下のように入力する。

self extent.

入力したところで、Command-P(Alt-P)を押すと、以下のように表示される。
extent
画面上に 50@40 と表示されているのが見える。これは、モーフの幅が50ピクセル、高さが40ピクセルであることを示している。
Smalltalkでは、歴史的にx@yの形式でXY座標値を表す。しかし、2個の成分を持ったベクトルデータは様々な使い道があり、特に成分が数値の場合には座標値を別の用途に用いることが多い。そのためモーフの幅と高さといったデータも座標値として表されている。
ちなみに、50@40から50を取り出したい場合には座標値にxというメッセージを送る。次のコードを見てみよう。

(50@40) x.

入力できそうなところならどこでも構わない(起動時に開かれる説明画面でもよい)ので上の2行を入力したあと選択し、Command-P(Alt-P)を押すと50という値が表示される。40を取り出すには、xの代わりにyというメッセージを送る。
Playgroundで入力した式を使ってモーフの幅だけを取得したいなら以下のように書けばよいが、後述するようにそのための特別なメッセージも用意されている。

self extent x.

モーフの大きさを設定したい場合には、extent:メッセージを送る。extent:はキーワードメッセージと呼ばれるもので、座標値で表した大きさを引数としてメッセージを送ればモーフの大きさを変えることができる。
Playgroundの右下のペインで入力したものを以下のように変える。

self extent: 100@100.

入力後にCommand-D(Alt-D)を押すと、モーフの大きさが変わる。
幅や高さを個別に取得したり指定したい場合は、それぞれ以下のようなメッセージを送ればよい。

width
幅の取得
width: 数値
幅の設定
height
高さの取得
height: 数値
高さの設定

キーワードメッセージの場合は、対応する値とともにメッセージを送る。
なお、Morphicではモーフの幅や高さを個別に管理しているわけではない。モーフの大きさは次回説明する位置情報とともに一括して管理されている。
(第2回おわり)

はじめてのMorphicチュートリアル(第1回)「Morphicとは」

Smalltalkの初心者に対してMorphicの使い方を紹介していく。なるべく簡易に少しずつMorphicについて学べるような内容を心がけていきたい。
SmalltalkではMVCモデルによるGUIが有名であるが、Morphicは最近の実装(Squeak, Pharo, Cuis等のSmalltalk)において、GUIを構築するフレームワークとして用いられている技術である。
このチュートリアルでは実装としてPharoを用いる。PharoはオープンなSmalltalk実装で、活発に開発が行われているものの1つである。
試しながら学ぶためにPharoのサイトでDownloadのページへ移り、Windows/Mac/LinuxなどのOSに応じた最新版をダウンロードしよう。
ダウンロードしたら適当なフォルダに展開してPharoのアプリケーションを起動する。
起動すると下のような画面が現れる。
起動画面
執筆時点の最新版は4.0である。毎年更新されて内容も大きく変わるが、Pharoはシンプルがモットーなので起動画面のイメージはバージョン間でそれほど変わらない。
まずは起動したPharoでモーフ(Morph)と呼ばれるオブジェクトを生成してみよう。背景を適当にクリックしてWorldメニューを出し、上から2つ目のPlaygroundを選ぶ。
Playground
Playgroundとは4.0からWorkspaceの代わりになったインスタントな操作環境である。Smalltalkの適当な式を評価することができるだけでなく、評価結果の詳細な分析もしやすくなっている。
モーフを生成するために、Playgroundに以下の式を入力してみよう。

Morph new openInWorld.

入力したらPlaygroundのタイトル右下にある緑色のボタン「Do it all and go」を押す。
すると下のような画面になる。
Morph
PharoのロゴのPに掛かるように現れた青い四角形が生成されたモーフである。
先ほど入力した式では、Morphというクラスに対してnewというメッセージを送ってモーフを生成し、更に生成されたモーフに対してopenInWorldというメッセージを送ってモーフを画面に表示させている。(Smalltalkでは連続したメッセージ式は左結合となる)
これがモーフの基本形であり、ここから様々なモーフを派生させていく。こんなシンプルなものでGUIまで作り上げていくんだからSmalltalkerはこわい。
(第1回おわり)
補足
チュートリアルを試している途中でやめたくなった場合、2通りの終了方法がある。
1つ目は今までやったことを残す方法で、デスクトップをクリックして現れるWorldメニューでSaveを選ぶ。
2つ目は起動後に行った行為を残さない方法で、デスクトップをクリックして現れるWorldメニューでQuitを選ぶ。
Pharoに限らずSmalltalkの多くの処理系では、ゲームに似た感覚で作業を残すか残さないかを決めることができる。