vieweditattachhistorytopchangessearchhelp

第76回


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


本連載では、名前は知っていてもなかなか触れる機会のないSmalltalkについて、最近話題のSqueakシステムを使って紹介しています。今回は、作成中のGUIビルダをいったん完成させます。

▼ウィジェット削除時の処理の修正
近々ご紹介したいと思っている、先頃リリースされた最新版のSqueak3.9での動作確認をしていたところ、うっかりミスに気付くことができましたのでこの機会に修正させてください。問題はウィジェットをレイアウトからクリックで削除するための#removeWidgetFrom:にありました。

removeWidgetFrom: window
  | clickPoint selected |
  clickPoint := Point fromUser.
  selected := window paneMorphs
     detect: [:morph | morph bounds containsPoint: clickPoint]
     ifNone: [].
  selected
     ifNotNil: [selected delete]


最後のdeleteだけでは不十分で、削除した結果をpaneMorphsに反映させるための#updatePanesFromSubmorphsをコールする必要があります。ウィジェット削除後、見えない枠変更用UIの亡霊たちに悩まされたかた、ごめんなさい(3.9ではこのUIが実体を持つように変更されたため、気が付きました…汗)。#paneMorphSatisfying:という便利メソッドも活用して次のように書き換えることにいたしましょう。

removeWidgetFrom: window
  | clickPoint selected |
  clickPoint := Point fromUser.
  selected := window
     paneMorphSatisfying: [:morph | morph bounds containsPoint: clickPoint].
  selected ifNotNil: [
     selected delete.
     window updatePanesFromSubmorphs]


▼ウインドウを生成するためのコード出力
仕上げには、GUIビルダ上でデザインしたGUIをコードとして出力するメニュー項目を設置します。必要な作業は二つ。ひとつは、もうお馴染みの、#addModelItemsToWindowMenu:の最後に該当記述を追加すること。メニュー項目名は「show script」、起動するメソッドは「#generateScriptOf:」としました。

addModelItemsToWindowMenu: aMenu
  window := aMenu defaultTarget.
  aMenu addLine.
  (self class allMethodsInCategory: 'widget types') do: [:widgetSym |
     aMenu
        add: 'add ', widgetSym
        target: self
        selector: #add:to:
        argumentList: {widgetSym. window}].
  aMenu addLine.
  aMenu add: 'delete' target: self selector: #removeWidgetFrom: argument: window.
  aMenu addLine.
  aMenu add: 'show script' target: self selector: #generateScriptOf: argument: window



必要なことのもうひとつは、呼び出される側の#generateScriptOf:を定義する


generateScriptOf: window
  | sourceCodes method widgetClass sourceCode file start frame |
  sourceCodes := Dictionary new.
  (self class allMethodsInCategory: 'widget types') do: [:selector |
     method := self class compiledMethodAt: selector.
     widgetClass := method literals
        detect: [:lit | lit asString beginsWith: '#Pluggable'].
     sourceCode := method getSourceFromFile asString.
     start := sourceCode indexOf: $^.
     sourceCode := sourceCode allButFirst: start + 1.
     sourceCodes at: widgetClass value put: sourceCode].
  file := FileStream newFileNamed: 'mywindow.st'.
  [  file nextPutAll: '| model window |'; cr.
     file nextPutAll: 'model := Model new.'; cr.
     file nextPutAll: 'window := '.
     file nextPutAll: '(SystemWindow labelled: ''My Window'') model: model.'; cr.
     window paneMorphs do: [:morph |
        file nextPutAll: 'window addMorph: ('.
        file nextPutAll: (sourceCodes at: morph class).
        file nextPutAll: ') frame: ('.
        frame := morph layoutFrame.
        file nextPutAll: (
           frame leftFraction @ frame topFraction
              corner: frame rightFraction @ frame bottomFraction) printString.
        file nextPutAll: ').'; cr].
     file nextPutAll: '^ window openInWorld']
  ensure: [file ifNotNilDo: [:f | f edit]]



少し長めなうえ、Smalltalkならではの機能を多用(乱用?)しているので、細かな解説は次回以降としますが、大枠ではこんなことをしています。

  1. 'widget types'に分類してあるメソッドのソースをカタログ化。
  2. 各ウィジェットからレイアウト情報を引き出す。
  3. ソースとレイアウト情報を組み合わせて加工し、スクリプトを構成。
  4. スクリプトをmywindow.stファイルに出力後、あらためてそれを表示。


正月休みをはさんで次回まですこし間があくので、これまでの復習を兼ねて、#generateScriptOf:の読み解きにチャレンジしてみてはいかがでしょうか。ちなみに、「show script」で現われたウインドウ内のコードを選択してdo it(cmd + D)すると、完成品のウインドウが得られます。スクリプトを変更して、適切なモデルと正しく接続すれば、アプリのGUIとして機能するようになります。こちらの解説もいずれ。

それでは、よいお年をお迎えください。

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


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

This page has been visited 270 times.