VisualWorks Smalltalk の“アプリケーションモデル”で BMI checker 2
id:sumim:20080919:p1 の続き。umejavaさんにコメントやメールで教えていただいたので、フィールドの色が変わる版も。複数のウインドウが共通のモデルを共有したときにも動作するように細工してみました。
| app1 app2 window1 window2 | app1 := BMIChecker4 new. window1 := app1 open window. app2 := BMIChecker4 new. app2 height: app1 height. app2 weight: app1 weight. app2 bmi: app1 bmi. window2 := app2 open window. window1 moveTo: 100@100. window2 moveTo: window1 displayBox topRight + (20@0)
前の BMIChecker との違い(=教えていただいて学んだこと)は、
- フィールドの色を変えるために、GUI Painter Tool → BMI値入力欄 → Basics → ID:欄 に #bmi を入力して、あとで #componentAt: でたぐれるようにしたこと
- #height、#weight、#bmi は、同じく GUI Painter Tool で対応する入力欄を選択した状態で Edit → Define で自動生成させたこと。それに伴い、
- ウィジェットビルド後にコールされる #postBuildWith: をフックして BMI値欄の色づけを伴う初期化を行なっていること
…といったところでしょうか。あと、モデル共有時に期待通りの動作をしなかったため今回は使いませんでしたが、#onChangeSend:to: のコールをハンドコードする代わりに、GUI Painter Tool → 各入力欄 → Notificationタブ → Change:欄で #bmiChanged などと入力して指定することでも似たようなことが可能であることも教えていただきました。
Smalltalk defineClass: #BMIChecker4 superclass: #{UI.ApplicationModel} indexedType: #none private: false instanceVariableNames: 'height weight bmi ' classInstanceVariableNames: '' imports: '' category: '(none)' BMIChecker4 >> initialize super initialize. self height value: 1.704. self height onChangeSend: #bmiChanged to: self. self weight value: 60.4. self weight onChangeSend: #bmiChanged to: self BMIChecker4 >> postBuildWith: aBuilder self bmiChanged BMIChecker4 >> bmi: aValueHolder bmi := aValueHolder BMIChecker4 >> height: aValueHolder height := aValueHolder. aValueHolder onChangeSend: #bmiChanged to: self BMIChecker4 >> weight: aValueHolder weight := aValueHolder. aValueHolder onChangeSend: #bmiChanged to: self BMIChecker4 >> bmi ^bmi isNil ifTrue: [bmi := 0 asValue] ifFalse: [bmi] BMIChecker4 >> height ^height isNil ifTrue: [height := 0 asValue] ifFalse: [height] BMIChecker4 >> weight ^weight isNil ifTrue: [weight := 0 asValue] ifFalse: [weight] BMIChecker4 >> bmiChanged | bmiValue component fieldColor | bmiValue := self weight value / (self height value ** 2). self bmi value: bmiValue. fieldColor := bmiValue < 18.5 ifTrue: [ColorValue white] ifFalse: [ bmiValue < 20 ifTrue: [ColorValue yellow] ifFalse: [ bmiValue < 30 ifTrue: [ColorValue orange] ifFalse: [ColorValue red]]]. component := self builder componentAt: #bmi. component lookPreferences: (component lookPreferences setBackgroundColor: fieldColor) BMIChecker4 class >> windowSpec "Tools.UIPainter new openOnClass: self andSelector: #windowSpec" <resource: #canvas> ^#(#{UI.FullSpec} #window: #(#{UI.WindowSpec} #label: 'BMI checker' #bounds: #(#{Graphics.Rectangle} 640 400 840 520 ) ) #component: #(#{UI.SpecCollection} #collection: #( #(#{UI.LabelSpec} #layout: #(#{Graphics.LayoutSizedOrigin} 15 0 15 0 46 18 ) #label: 'Height:' ) #(#{UI.LabelSpec} #layout: #(#{Graphics.LayoutSizedOrigin} 15 0 50 0 46 18 ) #label: 'Weight:' ) #(#{UI.LabelSpec} #layout: #(#{Graphics.LayoutSizedOrigin} 15 0 85 0 29 18 ) #label: 'BMI:' ) #(#{UI.InputFieldSpec} #layout: #(#{Graphics.LayoutSizedOrigin} 70 0 13 0 100 23 ) #model: #height #type: #number ) #(#{UI.InputFieldSpec} #layout: #(#{Graphics.LayoutSizedOrigin} 70 0 48 0 100 23 ) #model: #weight #type: #number ) #(#{UI.InputFieldSpec} #layout: #(#{Graphics.LayoutSizedOrigin} 70 0 83 0 100 23 ) #name: #bmi #model: #bmi #type: #number ) #(#{UI.LabelSpec} #layout: #(#{Graphics.LayoutSizedOrigin} 175 0 15 0 10 18 ) #label: 'm' ) #(#{UI.LabelSpec} #layout: #(#{Graphics.LayoutSizedOrigin} 175 0 50 0 16 18 ) #label: 'kg' ) ) ) )
ファイルイン用のファイルはこちらに。