parent previous next question (Smalltalk Textbook 04)

EngiVariable

In this section I describe how to display things in windows. Smalltalk has a framework called Model-View-Controller (also known as MVC). Every window is created based on this framework. Models are objects which hold the contents of the things we want to display in windows. Views are objects whose purpose is to display models. And controllers are specialized objects to handle operations and instructions to views or models. Models can have one or more dependent-objects which must be informed of changes in the model.

For example, suppose there is a variable object and an object displaying the contents of this variable. If the value of the variable object changes, then the object displaying the variable must change in turn. In this case, the variable object is called the model and the displaying object is a dependent object. Let's design a class for the variable object called 'EngiVariable'. You make an instance of this class as follows. (Please 'file in' Appendix 02 now).

--------------------------------------------------------------------
aVariable := EngiVariable new.
--------------------------------------------------------------------

In this case the value of 'aVariable' is 'nil'. If you want to set the value when 'aVariable' is created, you send the class message 'value:' to 'EngiVariable'.

--------------------------------------------------------------------
aVariable := EngiVariable value: 100.
--------------------------------------------------------------------

To change the value of 'aVariable', you send a 'value:' message to 'aVariable'. Please note that 'value:' is not a class message but an instance message. This next statement shows how to assign an instance of a picture you take from the screen to 'aVariable'.

--------------------------------------------------------------------
aVariable value: Image fromUser.
--------------------------------------------------------------------

This next statement shows how to access this value.

--------------------------------------------------------------------
| anImage aVariable  |
aVariable := EngiVariable new.
aVariable value: Image fromUser.
anImage := aVariable value.
^anImage
--------------------------------------------------------------------

The 'aVariable' object can hold more than one value. You can specify the number of values as an argument of 'new:' message, in which case you use the 'at:put:' message to set values of 'aVariable'. The following statements assign an instance of a picture as the first value, an instance of a rectangle as the second, and an instance of the numerical value 100 is as the third.

--------------------------------------------------------------------
aVariable := EngiVariable new: 3.
aVariable at: 1 put: Image fromUser.
aVariable at: 2 put: Rectangle fromUser.
aVariable at: 3 put: (EngiVariable value: 100).
--------------------------------------------------------------------

Use the 'at:' message to access values.

--------------------------------------------------------------------
anImage := aVariable at: 1.
aRectangle := aVariable at: 2.
anInteger := (aVariable at: 3) value.
--------------------------------------------------------------------

If you want to create a variable object with several values, use the 'values:' message. This next statement shows how to create an instance of 'EngiVariable' with 1000 as the first value, 2000 as second, and 3000 as third.

--------------------------------------------------------------------
aVariable := EngiVariable values: #(1000 2000 3000).
--------------------------------------------------------------------

You can see that the 'EngiVariable' class is a subclass of 'Model' by looking at Appendix 02. This allows 'EngiVariable' instances to have dependent-objects. To verify this, please 'file-in' the next example and 'do it' 'EngiDummyView example1'


Program-4-1: (EngiDummyView, EngiVariable, View; displayOn:, update:)
--------------------------------------------------------------------
View subclass: #EngiDummyView
      instanceVariableNames: ''
      classVariableNames: ''
      poolDictionaries: ''
      category: 'Engi-Dummy'!

!EngiDummyView methodsFor: 'displaying'!

displayOn: graphicsContext
      | aComposedText displayPoint |
      aComposedText := self model value printString asComposedText.
      displayPoint := self bounds center - aComposedText bounds center.
      aComposedText displayOn: graphicsContext at: displayPoint! !

!EngiDummyView methodsFor: 'updating'!

update: aSymbol
      self clearInside.
      self displayOn: self graphicsContext! !
"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!

EngiDummyView class
      instanceVariableNames: ''!

!EngiDummyView class methodsFor: 'examples'!

example1
      "EngiDummyView example1."

      | aVariable topView aDummyView edgeDecorator |
      aVariable := EngiVariable new.
      2
            timesRepeat:
                  [topView := EngiTopView
                                    model: nil
                                    label: 'Dummy'
                                    minimumSize: 100 @ 100.
                  aDummyView := EngiDummyView model: aVariable.
                  edgeDecorator := LookPreferences edgeDecorator on:
aDummyView.
                  edgeDecorator noMenuBar.
                  edgeDecorator noVerticalScrollBar.
                  edgeDecorator noHorizontalScrollBar.
                  topView add: edgeDecorator in: (0 @ 0 corner: 1 @ 1).
                  topView open].
      aVariable inspect! !
--------------------------------------------------------------------

After you 'do it', two windows labeled Dummy appear on your screen, each with the word 'nil' in its center. Also an inspector is created. In the right window of the inspector, type 'self value: 100', select that text and 'do it'. The 'nil' strings in the two windows change to '100' immediately. This demonstrates the value of the Model-View-Controller framework. When 'EngiDummyView model: aVariable' is executed, 'aDummyView' which is an instance of 'EngiDummyView' becomes a dependent-object of 'aVariable'. Whenever 'aVariable' receives a 'value:' or 'at:put:' message, it sends a 'changed:' message to itself and also sends 'update:' messages to its dependent-objects. 'EngiDummyView' class is simple. It displays the contents of the model at the center of the view and re-displays the view whenever it receives an 'update:' message. 'EngiDummyView' is a temporary class. Please delete it after exploring a little.


parent previous next question
Copyright (C) 1994-1996 by Atsushi Aoki
Translated by Kaoru Rin Hayashi & Brent N. Reeves