This tutorial explains some workings of morphic and shows how I implemented the GUI for the Subway Simulation Project.
The first step in working with morphic is to create a morphic world. A morphic world is the "canvas" to which all the widgets and other components are added. A morphic world is quite robust and supports adding objects as needed and allows for changes in color, and such, as well.
You create the world by typing:
aWorld := WorldMorph new initialize.
(is there a zeroth step? When I do this, I get a dialog saying aWorld is undefined and do I want to create it as a temp. When I do that, I get a dialog saying "aWorld" is unused in this method, ok to remove it?" - whisper@accessone.com)
Try to execute the line. Nothing occurs. This is because you must tell the world to show itself, so in the next line type the following:
aWorld openWithTitle:'Hello World'.
And like magic up comes and empty window with the title 'Hello World'. You are now in the world of morphic. You can start adding components by right clicking anywhere and picking 'new morph'. This brings up a menu of all available morphic objects and also includes any morphic objects you created by subclassing from existing morphic objects.
Let's add a simple button to the world.
1) Right click in the world.
2) Select the 'new morph' item.
3) Select Morphic-Widgets|SimpleButtonMorph.
4) Click anywhere to place your button.
You now have a morphic world with a button. Now experiment a little and add some other morphs to your world.
Another great feature of the morphs is that they can all be modified after being placed. Right clicking on our button brings up a menu of available modifications. Let's start by moving the button around.
1) Right click on the button and select grab from the menu.
2) Now move the mouse around and you can place the button anywhere you wish.
You can also make some other modifications such as resizing and color changing. Now try out some of the other modifications until you feel comfortable with it.
Now that we discussed how to add the buttons for our GUI, let's add an area where we will show the text for our output.
We will use a TextMorph to show the output. Now add a TextMorph to the world.
1) Right click the world and select 'new morph'|Morph-Basic|TextMorph.
You now have text area to show the output.
All this may be nice and neat, but when you close the window, gone are your morphs. You can get around this problem by adding morphs from within your program.
You can add a button by typing the following:
aButton := SimpleButtonMorph new initialize. "initialize the button" aButton bounds: (112@69 corner: 158@87) . "set up it coordiantes and size" aButton label:'Button Label'. "change the button label" aWorld addMorph: aButton. "tell the world to add the button"
You will now get a button added to your world. You may wonder where I got the value for my bounds. Like all objects, morphs can be inspected, and from there we can get some information about them.
Do the following to this:
1) Right click on your button and select 'inspect'.
You now have a new window showing all the variables of the morph. Now just place the button where you would like it and copy the bounds value after inspecting, and you have the coordinates to accurately place any object.
I will now show, step by step, how I created my user interface.
The first thing I did was make a new object and sublassed it off of SimpleButtonMorph. The reason for this: you must overwrite 'doButtonAction' method which defines what occurs when the button gets clicked.
In my doButtonAction the first thing I do is create a temprorary SubwaySimulation. This will let us access the output from the simulation. To ease the process, you should create methods in your program to return the output as a string.
Next I get the textArea I will be changing. I do this with the line: textArea := owner findA:TextMorph.
The owner is the worldMorph and is analogous to calling super. findA returns the textmorph that was added to the world.
The rest of the method goes through various tests to determine which button was clicked, and sets the textArea content accordingly.
This is probably not the best way to this, but it is the simplest and fastest. A better way involves changing the doButtonAction method when you set your button up, so the doButtonAction would be different for each instance of the button and no tests would be needed.
Now let's add the buttons to the morph. This is done as outlined above. So simply add as many buttons as needed to satisfy your button needs. You can get their coordinates by first placing them then inspecting them.
Do the same for the text area and you are done. Now every time a button is clicked, the text area should change in accord with the string return from the associated method.
I include the code for my button and output methods so you can play around with it some more.
Winter 1998
'From Squeak 1.3 of Jan 16, 1998 on 14 March 1998 at 3:31:15 pm'!
doButtonAction
"Perform the action of this button. Subclasses may override this method. The default behavior is to send the button's actionSelector to its target object with its arguments."
| textArea temp |
temp := SubwaySimulation new.
textArea := owner findA:TextMorph.