いきなりだが、とりあえずクラスを作ってみる。
定義するのはwindowSpecとコンボボックスのaspectとchoiseの三つ。
windowSpec
^#(#{UI.FullSpec}
#window:
#(#{UI.WindowSpec}
#label: 'Unlabeled Canvas'
#min: #(#{Core.Point} 20 20 )
#max: #(#{Core.Point} 0 0 )
#bounds: #(#{Graphics.Rectangle} 640 400 829 463 ) )
#component:
#(#{UI.SpecCollection}
#collection: #(
#(#{UI.ComboBoxSpec}
#layout: #(#{Graphics.Rectangle} 10 6 178 33 )
#name: #ComboBox1
#colors:
#(#{UI.LookPreferences}
#setSelectionForegroundColor: #(#{Graphics.ColorValue} #black )
#setSelectionBackgroundColor: #(#{Graphics.ColorValue} #white ) )
#model: #aCombo
#type: #timestamp
#formatString: 'yyyy/m/d h:mm:ss A/P'
#comboList: #aComboList ) ) ) )
aCombo
^aCombo isNil
ifTrue:
[aCombo := nil asValue]
ifFalse:
[aCombo]
aComboList
^(List with: Timestamp now) asValue
では画面をオープンして、コンボをクリックしてみよう。
何度クリックし直しても、プルダウンするのは画面オープン時の時刻だろう。
次に、aComboListを次のように書き換える。
aComboList
^[List with: Timestamp now]
そして画面を開き直し、コンボをクリック。
今度はクリックした時刻へと刻々と変化するのがわかる。
さて、ここで重要なのは、aComboListがValueHolderを返しても、ブロックを返しても、
何も問題なく動作したということだ。
どちらもvalueというメソッドを理解し、同じように中身を評価して返し、そして
コンボのプルダウンはvalueの返り値を表示しているからだ。
これこそがダックタイピングだ・・・なんといいかげんなという感じだが、valueという共通する
メソッドがあらかじめ定義されているおかげで、ComboBoxButtonXXXXクラスをいじることなく、
表層の画面クラスでリストを毎回評価するか、一回評価するか使い分けることができるというわけだ。
ちなみに、おそらくシンコムの開発者たちが意図していなかった使用法だと思う。
なぜなら、プルダウンウィンドウの高さを決めるためだけにself list sizeとかやっているからだ。
ブロックに対してこれをやると、ブロックの中身を何度も評価して非常にパフォーマンスが悪い。
結局・・・ブロックで実装するためにはComboBoxButtonViewクラスにリスト数を保持するための
インスタンス変数を追加することになるんだな・・・
最終更新:2012年08月22日 00:47