=== Top of the Swiki === Attachments ===

Morphic counter example

Draft


An simple example - let´s say a counter - helps to learn Morphic.
There are different approaches using Morphic. This unfinished tutorial should show and comment on them sometime in the future .

If you like to help please feel free to either add questions, comments or elaborate on the instructions. I (hh) will check this page from time to time and work on this if time permits.


First version



Andre M. (Mike) Maloney" asked in comp.lang.smalltalk
>
> Hi all,
>
> I'm just starting to learn smalltalk and am using Squak (2.4c).
> I'm trying to build a simple counter and need some help. The counter
> will have three buttons and a display. The displayed value will start
> at one and the buttons will increment the displayed value by one,
> decrement the displayed value by one, and reset the displayed value to
> zero.
> I've found the ValueHolder, button, and PluggableButtonController
> classes, but how do I put the buttons and ValueHolder into a parent
> frame (window?, view?)?


Squeak has two different interface models: the older MVC (Model, View,
Control), and the newer Morphic. The classes you found are part of
MVC. You can use these to build an MVC interface, but it is a little
more complicated than Morphic.

If you want to try your example using Morphic, do the following:

1) make sure you are in the Morphic interface. If your menus are white
with a blue frame around them, you are. Otherwise, select "open..."
then "project (morphic)" from the main display menu, then enter the
project by clicking on it.

2) Open up a Browser and have a look at the SameGame class; we're going
to borrow heavily from it, here.

3) Open up a Workspace and type in the following:


"this is going to be the box containing our panel"
frame := AlignmentMorph new
orientation: #vertical.

"create a 4-digit LED display to contain the count"
display := LedMorph new
digits: 4;
extent: (410@15).

"we want our buttons arranged in a horizontal row"
controls := AlignmentMorph new
orientation: #horizontal.

"add a quit button"
controls addMorph:
(SimpleButtonMorph new
target: frame;
label: 'quit';
actionSelector: #delete).

"add an increment button"
controls addMorph:
(SimpleButtonMorph new
target: display;
label: 'inc';
actionSelector: #increment).

"add a decrement button"
controls addMorph:
(SimpleButtonMorph new
target: display;
label: 'dec';
actionSelector: #decrement).

"add a clear button"
controls addMorph:
(SimpleButtonMorph new
target: display;
label: 'clear';
actionSelector: #clear).

"add the controls and display to our panel"
frame addMorph: controls.
frame addMorph: display.

"start playing with it!"
frame openInWorld


We're not quite ready to run it yet. We don't have anything to handle
the increment/decrement logic. To make this easy, we'll just add it to
the existing LedMorph class, which we are using for the display.

In the browser, find the LedMorph class, go to the "accessing" category,
and find the "value:" method. We'll just tweak this a few times to add
the new methods "increment", "decrement", and "clear".

First, select the bold method header (value: aNumber) and change it to
increment. Then replace the line "value := aNumber." with "value :=
value + 1.". Then accept your change (hit command-s or select "accept"
from the menu in the lower pane. Now do the same thing for "decrement"
and "clear" (doing the right thing with value).

Now we're ready to give it a try. Select everything you typed in the
Workspace and doIt (command-d or select doit from the menu). You should
now have a light green panel with buttons and an LED display.

-- Tim Olson



Second version: Assembling the Morphic counter by direct manipulation



It is possible to assemble a Morphic counter by directly manipulating morphs; however the following instructions need more elaboration.

Tim Olson gave the following hints as a starting point:

1) Get an alignment morph, from "new morph..."

2) Grow the alignment morph by right-clicking (or command-clicking on

Mac) to get the halo, then resize with the yellow handle.

3) get an LedMorph and some SimpleButtonMorphs on the desktop.

4) right-click on a button (or cmd-click on Mac) to bring up the halos,

and click the red handle to bring up a menu.  change the button's
label

and selector (increment, decrement, etc).

5) [this is the step that doesn't work for me anymore...] you should
be

able to pick up a button morph with the black halo handle, and move
it

on top of the LedMorph.  When you look at the button's menu, it
should

have a new entry that allows you to set the button's target. 
However,

it's not working for me anymore under 2.5 (running with a 2.4VM under

LinuxPPC).

6) pick up & drop the LedMorph and buttons onto the alignment morph,
and

choose "embed..." from their menus.

        -- tim

 



Third version: Separating the UI, the business logic and the application


The following example implementation of the Morphic Counter  uses
three classes.

Mark Mayfield wrote to the Squeak mailing list on  Thu, 19 Aug
1999:

Being someone that is a purest at heart when it comes to separating

business logic, i.e. the model, from its interface, i.e. a view
and


controller, here is an alternative to Tim's example. It's a little

more work, but it keeps the LedMorph more of an "interface" object
by


making it pluggable. The counter object is a model object, and the

counting application is a cooridnator object in that it creates
the


counter and pluggable led morph objects and connects them up.

It's not the best code in the world, but it gets the point across.

He also wrote on Monday, 16 Aug 1999

To me a morph is a combination of a view and a controller. I still

create separate model objects that have morphs as dependents.

The three classes




His code:

Model subclass: #Counter

 instanceVariableNames: 'currentValue '

 classVariableNames: ''

 poolDictionaries: ''

 category: 'Counting'!

!Counter methodsFor: 'initialize-release' stamp: 'mlm 8/14/1999
09:30'!


initialize

 currentValue _ 0.! !

 

!Counter methodsFor: 'accessing' stamp: 'mlm 8/14/1999 09:29'!

currentValue

 ^ currentValue! !

!Counter methodsFor: 'accessing' stamp: 'mlm 8/14/1999 09:29'!

currentValue: anObject

 currentValue _ anObject.

 self changed: #currentValue! !

 

!Counter methodsFor: 'counting' stamp: 'mlm 8/14/1999 09:31'!

clear

 self currentValue: 0! !

!Counter methodsFor: 'counting' stamp: 'mlm 8/14/1999 09:32'!

decrement

 self currentValue: self currentValue - 1! !

!Counter methodsFor: 'counting' stamp: 'mlm 8/14/1999 09:32'!

increment

 self currentValue: self currentValue + 1! !

"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!

Counter class

 instanceVariableNames: ''!

!Counter class methodsFor: 'instance creation' stamp: 'mlm 8/14/1999
09:34'!


new

 ^ super new initialize! !



Model subclass: #CounterApplication

 instanceVariableNames: 'counter frame display controls '

 classVariableNames: ''

 poolDictionaries: ''

 category: 'Counting'!

!CounterApplication methodsFor: 'user interface' stamp: 'mlm 8/16/1999
13:25'!


openAsMorph

"create a model object"

counter _ Counter new.

"this is going to be the box containing our panel"

frame := AlignmentMorph new

 orientation: #vertical.

"create a 4-digit LED display to contain the count"

display := (PluggableLedMorph on: counter value: #currentValue)

 digits: 4;

 extent: (410@15).

"make the display a dependent of the model"

counter addDependent: display.

"we want our buttons arranged in a horizontal row"

controls := AlignmentMorph new

 orientation: #horizontal.

"add a quit button"

controls addMorph:

 (SimpleButtonMorph new

  target: frame;

  label: 'quit';

  actionSelector: #delete).

"add an increment button"

controls addMorph:

 (SimpleButtonMorph new

  target: counter;

  label: 'inc';

  actionSelector: #increment).

"add a decrement button"

controls addMorph:

 (SimpleButtonMorph new

  target: counter;

  label: 'dec';

  actionSelector: #decrement).

"add a clear button"

controls addMorph:

 (SimpleButtonMorph new

  target: counter;

  label: 'clear';

  actionSelector: #clear).

"add the controls and display to our panel"

frame addMorph: controls.

frame addMorph: display.

"start playing with it!!"

frame openInWorld! !

"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!

CounterApplication class

 instanceVariableNames: ''!

!CounterApplication class methodsFor: 'instance creation' stamp:
'mlm 8/16/1999 13:25'!


openAsMorph

 "CounterApplication openAsMorph"

 ^self new openAsMorph! !



LedMorph subclass: #PluggableLedMorph

 instanceVariableNames: 'getValueSelector model '

 classVariableNames: ''

 poolDictionaries: ''

 category: 'Counting'!

!PluggableLedMorph methodsFor: 'initialize-release' stamp: 'mlm
8/16/1999 13:05'!


on: anObject value: aSelector

 self model: anObject.

 self getValueSelector: aSelector! !

 

!PluggableLedMorph methodsFor: 'accessing' stamp: 'mlm 8/16/1999
13:03'!


getValueSelector

 ^ getValueSelector! !

!PluggableLedMorph methodsFor: 'accessing' stamp: 'mlm 8/16/1999
13:05'!


getValueSelector: aSelector

 getValueSelector _ aSelector! !

!PluggableLedMorph methodsFor: 'accessing' stamp: 'mlm 8/16/1999
13:02'!


model

 ^ model! !

!PluggableLedMorph methodsFor: 'accessing' stamp: 'mlm 8/16/1999
13:05'!


model: aModel

 model _ aModel! !

 

!PluggableLedMorph methodsFor: 'updating' stamp: 'mlm 8/16/1999
13:06'!


update: aSymbol

 aSymbol == getValueSelector

  ifTrue: [^ self value: (self model perform: self getValueSelector)]!

"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!

PluggableLedMorph class

 instanceVariableNames: ''!

!PluggableLedMorph class methodsFor: 'instance creation' stamp:
'mlm 8/16/1999 12:59'!


on: anObject value: aSelector

 ^ self new on: anObject value: aSelector! !

 

 


Source: mailing list archive
topic: "Simple Morphic project".
(http://macos.tuwien.ac.at:9009/Server.home)



Other version


Janak on Morphic UI: http://www.cc.gatech.edu/fac/mark.guzdial/squeak/morphicui.html




Exercise


Try to do a counter which counts seconds. Send a email to hh if you like to have a solution example.


last edit 02 Oct 99 / hh