vieweditattachhistorytopchangessearchhelp

第71回


■SqueakではじめるSmalltalk入門   第71回  鷲見 正人


本連載では、名前は知っていてもなかなか触れる機会のないSmalltalkについて、最近話題のSqueakシステムを使って紹介しています。前回は「#addFieldTo:」というメソッドをGuiBuilderクラスに定義しました。

addFieldTo: window
 | field |
 field := PluggableTextMorph
   on: self text: nil accept: nil readSelection: nil menu: nil.
 window addMorph: field frame: (0.5 @ 0.5 extent: 0.5 @ 0.5)


このメソッドは、GUIビルダウインドウのウインドウメニューに新たに設けられた「add field」というメニュー項目を選択したときに起動され、ウインドウの右下にウインドウサイズの四分の一の大きさのテキストフィールド(aPluggableTextMorph)を設置します。

ウインドウサイズの右下に四分の一の…というのは、最終行で起動されるメソッド#addMorph:frame:の第二パラメータである「0.5 @ 0.5 extent: 0.5 @0.5」という式で生成される矩形情報(a Rectangle)により指定されています。表示領域の中央(0.5 @ 0.5)から、縦横幅の半分の大きさ(extent: 0.5@ 0.5)で…という感じでしょうか。ウインドウ内の任意の位置にテキストフィールドを設置するには、この矩形情報を動的に生成する仕組みを設ければよさそうですね。

マウス操作でインタラクティブに矩形情報を生成するには、すでに第64回で予習したとおり、クラスRectangleにメッセージfromUserを送信するのがお手軽です。直後に画面に描いたのと同じ対角線情報を持つ矩形オブジェクトを得ることができます。

ただし、そのままでは#addMorph:frame:を起動するメッセージの第二パラメータとしては使えません。この第二パラメータには、新たに追加するウィジェットの画面上での位置ではなく、ウインドウに対する相対的な位置と、ウインドウの幅を1.0、高さを1.0としたときの相対的な大きさで指定しなければならないからです。

相対的な矩形情報への換算(全体の何割に当たるのか…)には、基準となる特定のウインドウの表示領域(タイトルバーを除いた…)の矩形情報が必要となりますが、これはウインドウにlayoutBoundsというメッセージを送ることで得られます。さらにその矩形情報にメッセージtopLeftを送れば左上の座標を、widthやheightを送れば幅や高さの情報を(extentを送れば、双方をa Pointとして同時に)得ることが可能です。

これら一連の情報を用い、座標や大きさ(いずれもa Pointで表現…)同士の二項演算を行なうことで、必要な換算式は比較的簡潔に記述できます。たとえば次のスクリプトでは、rectに関連づけされたRectangle fromUserが返す絶対座標の矩形情報を、そのスクリプトが入力されている(つまり、最前面の)ウインドウ表示領域に対する相対比値に変換して返します。

| rect window bounds relOrigin relExtent |

rect := Rectangle fromUser.
window := SystemWindow classPool at: #TopWindow.
bounds := window layoutBounds.
relOrigin := (rect topLeft - bounds topLeft) / bounds extent * 1.0.
relExtent := rect extent / bounds extent * 1.0.

^ relOrigin extent: relExtent


さらに、クラスRectangleには、レシーバを第一パラメータとして添えた別の矩形の相対座標に変換してくれる#scaleFrom:to:という便利なメソッドがあるので、これを使うのもよさそうです。ただ、この#scaleFrom:to:は結果を整数にまるめてしまうため、0.0〜1.0の間の数で割合を表現したい今回は、そのままでは使えません。そこで、同じくRectangleに定義されている#scaleBy:を組み合わせて結果を1.0以下の小数で算出できるよう工夫します。

| rect window bounds |

rect := Rectangle fromUser.
window := SystemWindow classPool at: #TopWindow.
bounds := window layoutBounds.

^ (rect scaleFrom: bounds to: (0 asPoint extent: 1e3 asPoint)) scaleBy: 1.0e-3


以上をふまえて、ウインドウメニューから「add field」を選択したときに、任意の大きさのテキストフィールドを設置できるよう冒頭のGuiBuilder >>#addField:to:を書き換えてみましょう。

addFieldTo: window
 | field relFrame |
 field := PluggableTextMorph
   on: self text: nil accept: nil readSelection: nil menu: nil.
 relFrame := (Rectangle fromUser
   scaleFrom: window layoutBounds
   to: (0 asPoint extent: 1e3 asPoint)) scaleBy: 1.0e-3.
 window addMorph: field frame: relFrame


「add field」選択後、マウスで描いた矩形がその場でテキストフィールドに置き換わり、きちんとGUIビルダウインドウに設置されれば成功です。

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


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

This page has been visited 276 times.