vieweditattachhistorytopchangessearchhelp

第65回


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


本連載では、名前は知っていてもなかなか触れる機会のないSmalltalkについて、最近話題のSqueakシステムを使って紹介しています。今は、簡単なGUIビルダを構築することを目指して、そのために必要なテクニックや知識を整理しているところです。

前回は「fromUser」というメッセージを、座標や矩形を表現するクラスに送信することで、直後のマウス操作から情報をオブジェクトとして情報を引き出すことが可能であることを確認しました。たとえば、RectangleクラスにfromUserメッセージを送れば、「Rectangle class >> #formUser」というメソッドが起動し、直前のマウスドラッグ操作で描いた矩形の座標を得ることができます。この方法で、位置や大きさをあらかじめ指定して、新しいウィジェットを設置する操作が実現できそうです。さっそく試してみましょう。

| field |
field := PluggableTextMorph new.
field editString: ''.
field bounds: Rectangle fromUser.
field openInWorld


とりあえず、このスクリプトの全体を選択し、do it(cmd + D)で実行してみてください。マウスポインタが十字(クロスヘア)に変化するので、画面の任意の位置でドラッグして矩形を描くと、ぴったりその位置にテキスト編集用のフィールドが現れます。

[fig.A,B]Rectangle fromUserの位置にテキストフィールドを生成
Uploaded Image: 65a.png
Uploaded Image: 65b.png

念のため、スクリプトの内容を順を追って解説してみましょう。まず最初は、テンポラリ変数「field」の宣言文。続けて、PluggableTextMorphのインスタンス(a PluggableTextMorph)を作り、その変数「field」に束縛しています。

fieldに束縛されたa PluggableTextMorphの初期化のために、メッセージ「editString: ''」を送った後、くだんのRectangle fromUserを使って得た矩形情報(a Rectangle)をパラメータに添えて、#bounds:というメソッドを起動しています。この#bounds:メソッドはMorphに定義されていて、モーフの位置と大きさを一発で決めることができます。つまり、

| morph |
morph := Morph new.
morph bounds: (100@100 extent: 100@100).
morph openInWorld


は、

| morph |
morph := Morph new.
morph position: 100@100.
morph extent: 100@100.
morph openInWorld


と同じことをします。

位置と大きさを決められたa PluggableTextMorphは、最後にopenInWorldメッセージを受け取って、我々の前にその姿を現わします。ただ、実際のシステムウインドウに埋め込む作業には、#add:frame:を起動するだけでよいので、#bounds:以下は、軽く流していただいて結構です。

さて、このように単に作られただけのテキストフィールド(aPluggableTextMorph)は、テキストの入力などの基本的な機能こそ正常ですが、モデルに依存する黄ボタンメニューを出すことができません。第62回のときは“魂”を欠いた状態などと抽象的に表現していましたが、実装的には、どんなことが起こっているのかを探ってみることにします。

とりあえずは、黄ボタンメニューを出すことだけを考えてみます。まず手始めに、手本となったワークスペースでテキストフィールドを作っているときのメッセージをそのまま真似てみることにしましょう。

PluggableTextMorphを選択して、cmd + shift + Nとタイプすると、そのクラスを含むメソッドの一覧をブラウズできるので、その中から、StringHolder >#openAsMorphLabel:inWorld:というメソッドを探して定義を見ると、次のようなワークスペースのウインドウを構築する記述が見つかります(改行の位置はわかりやすいように変えました)。

window
  addMorph: (
     PluggableTextMorph
        on: self
        text: #contents
        accept: #acceptContents:
        readSelection: nil
        menu: #codePaneMenu:shifted:)
  frame: (0@0 corner: 1@1).


ここで、#on:text:accept:readSelection:menu:を起動する際に添えられているパラメータを、そのまま真似ればよいのですが、他のパラメータと違い、第一パラメータのselfだけは文脈に依存する擬変数なので、別のものに置き換えなければいけません。

ワークスペースが作られるときの文脈では、このメソッド(StringHolder >> #openAsMorphLabel:inWorld:)を起動したワークスペースのインスタンス(aWorkspace)がselfに束縛されていることになりますから、このことを考慮して、冒頭のスクリプトを書き換えると次のようになります。

| field |
field := PluggableTextMorph
  on: Workspace new
  text: #contents
  accept: #acceptContents:
  readSelection: nil
  menu: #codePaneMenu:shifted:.
field bounds: Rectangle fromUser.
field openInWorld


改めてスクリプト全体を選択してdo it(cmd + D)すると、今度のテキストフィールドは、黄ボタンメニューも使えるようになっていることが確認できるはずです。

[fig.C]黄ボタンメニューをポップアップさせたところ
Uploaded Image: 65c.png

じつは、セレクタのキーワードから想像できるように、黄ボタンメニューを出すだけなら、最初と最後のパラメータだけをきちんと渡せば、あとはnilでも目的を果たすことができます。

| field |
field := PluggableTextMorph
  on: Workspace new
  text: nil
  accept: nil
  readSelection: nil
  menu: #codePaneMenu:shifted:.
field bounds: Rectangle fromUser.
field openInWorld


このことを手がかりに、次回、黄ボタンメニューがどのように呼び出されているのかを、もう少し掘り下げて調べてみることにします。

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


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

This page has been visited 782 times.