Last updated at 2:18 am UTC on 3 April 2007
A Morphic Fascination
I started this little tutorial project because I have long been interestsed in Smalltalk as a programming language but have found myself more drawn to direct-manipulation programming environments over the years. I took to HyperCard and its scripting language HyperTalk like a native speaker, wrote several books on it, built more functioning and usable products and code in it than anything else before or since, and lamented its demise.
When I saw Squeak Morphic for the first time, I felt genuine joy. Perhaps the possibility of combining my favorite programming language (Smalltalk) and direct-manipulation programming through the Morphic classes would be at long last realized. Believe me, I know how romantic this sounds ("romantic" not in the sense of amorous love but in the sense of wishful thoughts fulfilled).
In my Smalltalk books, I often started readers off by showing them how to build a simple counter containing three buttons – increment, decrement, and reset – and a text or number object whose value would change in response to button-clicks. So it was only natural that when I saw Squeak I would attempt to re-create that simple application as my own first learning step.
A fairly long time has elapsed since my first pass at this project and today's completion and preparedness to offer a tutorial and some insights. Along the way, I've made as many missteps as one probably could in such a simple endeavor. True to the philosophy of my Smalltalk books, I am preserving here some of those false steps in the hopes of helping you avoid those pitfalls in your own development work. Probably you will be among those who will say something like, "Well that was dumb. I wouldn't even have thought to go down that stupid path!" Good for you. I mean that. But for me, things weren't quite so obvious, and I had to learn some things the hard way. If you are among the tiny minority that are as bewildered by the largely undocumented Morphic world in Squeak as I am, perhaps you'll pick up a gem or two here.
(My plan is to turn this HTML page into a SqueakBook in the near future, by the way. That's how all tutorials and other lengthier documentation should probably be done in Squeak.But that's another learning curve and I wanted to get this published sooner than that route is going to permit. The limitations of HTML will prevent me from doing the "live" tutorial I envision for the moment.)
I'm presenting here a basic "recipe" for building this Counter project in Squeak. This technique works in Squeak 3.0; if you're using a different version, you might find it doesn't work. If that happens, you should post your question on the Squeak Mailing Lists.
This tutorial is now much revised and greatly simplified thanks to great feedback from the Squeak mailing list. If you read an earlier version and you're wondering where the complicated stuff went, know that I simply made things harder than they had to be.
On April 18, 2001, I added a whole section about some even more efficient ways of doing this project. I kept the original tutorial intact because I think it still teaches valuable stuff that might be useful in less trivial projects, but if you want to look at how much easier this is even than described here, or if you're just interested in a streamlined walk-through of Morphic, click here.
Step 1: Create a Morphic Project
I'll assume you've downloaded and installed Squeak on your system and that it's running successfully.
Clicking anywhere in a Squeak window that isn't occupied by some other component will bring up the World Menu. On that menu, select "Open..." and then "morphic project" (the last item on the standard world menu). This will create a thumbnail of a new Morphic project on your desktop. Click on it once to open it.
(HINT. Each time I create a new Morphic Project, the first thing I do is open the World menu and choose "keep this menu up" from near the top of the menu. Then I click on "new morph..." and then on "keep this menu up" in the resulting menu. Position these two menus conveniently in your layout depending on where and how you like to work. Saves tons of time later.)
Step 2: Create a Container Morph
We're going to be creating three buttons and a text object. There's nothing in Morphic that says these have to be grouped together in a single container; it would be perfectly legal (though perhaps a bit disorienting) to just scatter these components around in our Morphic Project. But just to be neat and tidy about things, let's start by creating a container for our Counter objects to live in.
A simple rectangular area to confine the objects will do nicely; we don't need any special or complicating behaviors. So we'll just use a rectangle. Click on the Supplies flap at the bottom of your Squeak screen and then click and drag on the gray rectangular object just to the left of the bright yellow ellipse. Position the new rectangle where you want it. Alternatively, you can use the "Add a new morph" menu. From the "Basic" menu at the top of this menu, pick "RectangleMorph" and then position your cursor (which will be followed politely by a RectangleMorph object) where you want to work. Then just click.
You'll almost certainly want to resize this RectangleMorph because it's pretty small to hold three buttons and a piece of text. Bring up a "Halo" of handles on the RectangleMorph by Command clicking on a Macintosh or Alt-left-clicking on a Windows machine (or right-clicking on a three-button mouse on Unix). This halo is one of the key things you work with in Morphic; roll your mouse over each of the handles and read the balloon help that pops up so you get familiar with the meanings of the handles.
Grab the yellow handle in the lower right corner of the halo on your RectangleMorph and resize the object to your taste. Something that's about 2 inches by 2 inches will suffice.
Step 3: Add a Displaying Value
We want the user to be able to see the effects of clicking on the buttons we're going to be putting into our Counter, so the first thing we'll do is place an object capable of holding a value and displaying it into our Counter. It turns out Morphic has a bunch of such objects, some of which have quite promising-sounding names. Particularly if you've had some experience programming in text, you'll be tempted to pick on something like an UpdatingStringMorphWithArgument object.
What I found in my various failed experiments at creating this simple counter initially was that, as is often the case, simple is better.From the Basic menu of the Add a new morph menu, pick a TextMorph. (a StringMorph is almost as good but it doesn't let you set its font and style, so you can't make the finished Counter look quite as good as you'd like.)
Drag this object into the RectangleMorph that I'll now start calling the Counter. Place it close to the right side of the layout area and center it between the top and bottom edges of that area. (Don't sweat this too much; you can always move it later and fine-tune it.)
Step 4: Give the Displaying Value a Value
The purpose of our Counter is to add to and subtract from a number. But at the moment, our TextMorph is displaying a value that won't be terribly easy to add to or subtract from because it's a string. So how do we make it into a number? This was one of the places I stubbed my toe repeatedly before getting help from Alan Kay of Squeak Central (the folks who bring us this great tool).
You might think that by simply editing the TextMorph's value right there in the Counter and making it into a zero, you'd have a counter which was ready to start adding and subtracting like mad. Nope. See, all you'd be putting into the TextMorph is a single string character "0". That string doesn't know anything more about adding and subtracting than the original string, "Text for Editing." What we have to do is to remember that this TextMorph is an object. It needs a property that gives it a numeric value so that we can then manipulate that value and see it grow and shrink before our very eyes.
But how to do this?
Open a viewer on the TextMorph. You do this by getting its halo and then clicking on the light blue eye handle on the left side of the halo. The viewer opens in the upper right corner of your screen.
While we're here, let's change the name of this object from its default of "text" to something meaningful. Just click on the word "Text" in the upper part of the viewer and type in a new name. We'll call this the "CounterDisplay". After you press Return to accept your new name, notice that all of the labels in the viewer change to reflect the new name. I thought that was pretty nifty the first time I saw it!
Now we are going to give this CounterDisplay a numeric value it can display for us. To do this, click and hold on the menu icon immediately to the left of the new name you just gave the object and select "add a new instance variable." In the dialog box that comes up next, type "counterValue" for the name of this new instance variable or press return or enter.
In a moment, a new pane will open at the top of the viewer. It will be labeled "instance variables" and it will have one entry indicating that "CounterDisplay's counterValue" has a current value of some number. (The number is immaterial and as far as I can tell not all that predictable.) The big purple and green arrow is very important and we'll get to its meaning shortly.
Step 5: Add the Increment Button
We're set up now to add our first button to the Counter. We'll start with the Increment button because in my layout, it's the topmost button in the Counter.
Choosing which of the many kinds of buttons to use for this project turned out to be another interesting adventure for me. I scanned through the names of all of the kinds of buttons available on the "Add a new morph" menu and initially decided to use what is called a "SimpleButtonMorph." I made that choice because, frankly, I figured all I needed was a simple button. That turned out to be an error. SimpleButtonMorphs are designed so that they flash when they're clicked (which is cool) but they "eat" their mouse-clicks rather than easily letting you hook up those mouse-clicks to things you want to happen (like updating the counter's value).
After a lot of fumbling, and a not-inconsiderable amount of help from the very patient members of the Squeak mailing list, I found that what I really wanted to use was a BasicButton.You will find this Morph, strangely enough, on the Scripting sub-menu of the "Add a new morph" menu. (You can also use the alphabetical list in the top part of the "Add a new morph" menu when you know the name of the Morph you want.)
Drag one of these little yellow buttons into your Counter. (No need to embed it. For reasons I don't fully understand, BasicButton objects automatically embed into the containers you place them in.) From its halo, choose its red menu handle and edit its label to read "Increment." You can also change its color from that menu while you're here if you like. I changed it to white because I don't like yellow buttons, but some people are partial to them. Go figure.
Step 6: Script the Increment Button's Function
From here you could proceed in a number of ways. You could, for example, place the other two buttons and get them all lined up nice and neat. Me, I'm an instant-gratification kind of guy so I go for the action right off. Let's attach a script to this Increment button so it will increment the value of our CounterDisplay.
Open the Increment button's viewer (halo, aqua eye handle), then from the small menu icon in the title bar of the viewer select "add a new script". A script tile attaches itself to your cursor. Position it where you want to work with it and then click. You have a new script ready to be told what to do. This scripting tile stuff is the brains of Morphic.
Again, there is no magic sequence to the next few things we're going to do. The first thing we'll do is add an instruction to this script.We want the CounterDisplay's value to increase by one each time the user clicks on this button. So we need to give our script access to the CounterDisplay's instance variable. How do we do that? Just like we do everything else in Morphic when we're using direct-manipulation programming: we drag a copy of the thing we want into the scripting window.
Notice that the viewer for your Increment button has a small tab to its left near the top. Clicking on this button slides the viewer into the right side of the window. Go ahead and do that. You should now see two such icons in the upper right corner of the screen. The bottom one is the tab for your Increment button's viewer. The other is the viewer for your CounterDisplay text object, which politely slid itself out of view when you opened the viewer on your Increment button. Click on that top icon and you'll see the viewer for CounterDisplay again.
Now, click and drag the purple and green arrow in the instance variable area and drag into the scripting tile window you just created. Keep going until you see a small green rectangle appear in the bottom of the script window. This indicates the first line of the script is ready to accept what you're dragging in. Just drop the scripting tile. Your script should expand and you should see a copy of the tiles indicating that CounterDisplay's counterValue is 2 (or whatever value yours started life with).
This script consists of three tiles. The first identifies the object and even has the good sense to make it possessive so it reads naturally. The second tile names the instance variable and has a left-pointing arrow (which is Smalltalk for "is assigned the value"). The third tile gives us an exact number for the counterValue.
Notice that both the second and third tiles have small sets of up- and down-pointing green arrows and that the third tile has a right-pointing arrow as well. These arrows are like pushbuttons; they let you work with the contents of each tile and, in the case of the right-pointing arrow, expand to add one or more additional tiles appropriate to the function of the object to which it's attached.
Click on the right-pointing arrow next to the number which represents counterValue's current value. It expands the script to add two more tiles. The first is an arithmetic operator tile (which in turn has green up-and-down arrows) and the second is a number tile which has a value of 1 for the moment. The right end of the script line now has two green arrows, one pointing right and one pointing left. Click the left one to return to the original script.
We want this script to take the current number stored in counterValue and add one to that number. My first way of doing that was to experiment a bit and discover that I could drag just the name of the instance variable from the CounterDisplay's viewer into the place now occupied by the number tile. It would replace the number. Then I could expand the script and add a "+1" set of tiles to the result.
That turned out to be far more work than I needed to do. This is a lesson in exploration. When you see things to click on in Morphic, go ahead and click on them! So check this out. Click on the up-pointing arrow to the left of "counterValue" in the script and watch what happens. Yep. You get an "increase by" replacing the assignment arrow that was there a moment ago. Click that button a couple more times and you'll see that you can also get it to decrease itself or multiply itself. This is too easy.
After you've been sufficiently amazed, return the counterValue tile to its "increase by" position. Now click on the down-pointing green arrow next to the value in your number tile until it is 1.
(This might be a good time to save your Squeak image if you haven't done so for a while.)
OK, ready for a test run of the script? We can do this without even officially hooking it up to the button. We do this by clicking on the yellow exclamation point to the left of the top of the script tile.This executes the script one time. Holding the mouse down executes it repeatedly until you release the mouse.
Click once. What happened? The Counter's still showing "Text for Editing" instead of the value we'd expect it to be showing now. What's wrong?
Step 7: Displaying the Value
It turns out that since the instance variable counterValue isn't connected to the text being displayed by the TextMorph called CounterDisplay, running the script does not have the effect we expect. You can see, however, that the script is working because as you click on the exclamation point, the value associated with the instance variable in the viewer itself changes.
We obviously have some disconnect here. This one stumped me for a while until, once again, the helpful Squeak listers chimed in. To make an instance variable visible in the project, you have to create what is called a "simple watcher" for it. Click on the little dot to the left of the counterValue instance variable in the viewer and hold until you ssee a menu pop up. Pick "simple watcher" and then move your mouse into the Counter area again and drop the value there. You should now see a small number object holding whatever the value of the instance variable is at this point.
Now click on the exclamation point in the script window and you'll see the value increase by one each time you click. (Actually, I saw it increase by two many times. It's a functcion of clock timing on your system. But don't worry, once we move to the button itself doing this work, it will work correctly.)
While we're at it, let's change the font and size of the displayed value. Get the halo and then the click the red menu button. Pick "font size..." and choose something you like.
Step 8: Hooking the Script to the Button
Right now, we have a script that is associated with the button but clicking the button itself doesn't do anything. That's because this script, like all Morphic scripts by default, is set up to run only when it's called. Clilcking on the exclamation point calls it. Nothing else does yet. What we really want is for the script to execute when the user clicks and releases the mouse over the button. This is called a "mouseUp" event.
In the area of the scripting tile where the word "normal" appears, click and hold and pick "mouseUp" from the new menu. Now click on the Increment button in the Counter and you should see the value update as expected.
Step 9: Creating the Decrement Button
We could go through Steps 5 and 6 again to create the Decrement button, but there's a much faster way (which helps explain why I chose the sequence I did to create this project). In Squeak, if we duplicate an object that has a script associated with it, the script gets duplicated as well. We can then modify the script to do what we want.
Bring up the halo on the Increment button and then click and drag from the green "copy" handle in the upper right corner of the halo. Drop the new button below the Increment button near the vertical center of the Counter.When you release it, its halo remains visible. Click on the red menu handle and edit its label to read "Decrement."
Get its halo again and open a viewer for it. Find the script associated with it and drag it out into your world.
Click on the down-pointing green arrow next to "counterValue increase by" until the "increase by" changes to "decrease by." Click on the Decrement button in the Counter and notice that it has the desired effect of reducing the value of the counter by one.
Step 10: Creating the Reset Button
Duplicate either of the existing buttons one more time, change its label to "Reset", open a viewer on it and drag out its script.
Click on the down-pointing green arrow in the counterValue tile until the assignment arrow returns as the next part of the tile. Then change the number being assigned, if necessary, to 0, using the up-and-down green arrows next to the number. Make sure the current counterValue is not zero, and click on the Reset button.
Step 11: Clean Up After Yourself
There is one remaining issue with the Counter. Right now, it has both the counterValue showing the numeric value of the Counter and a bit of editable text that probably still says "Text for Editing." We don't need this second piece of junk hanging around but it's not clear it is prudent to delete it since the counterValue is an instance variable contained in it and we might undo all our good work.
There is, it turns out, a simple (if not entirely correct) solution. Bring up a halo on the TextMorph called Counter Display, open its "miscellaneous" pane from one of the small popup menus in any pane in the viewer, and find the tile marked "Counter Display hide." Click once on the exclamation point next to it. Poof. Gone but not forgotten.
Concluding Thoughts First Time Around
There is a lot more to Morphic, of course. In fact, this tutorial doesn't even present the easiest or fastest way of accomplishing what I set out to to here. (See the next section, "Things I Learned After Publishing This Tutorial.") As I learn more and more about Morphic, I plan to add tutorials and other documentation to this site.I may also come back from time to time and add notes to this first-round attempt at learning what I think is the most exciting software development environment to come along in my lifetime.
Things I Learned After Publishing This Tutorial
It turns out that TextMorphs have a property I didn't know about when I set out on this adventure. Using this property and one other trick greatly simplifies the process of creating the Counter by direct manipulation in Morphic.This section discusses those techniques and how they affect the 11-step tutorial above. I decided to leave the original tutorial in place and supplement with this because, again, the value of the learning experience seems to me to be pretty high. I will, however, publish a revised tutorial to accompany this work that takes a very straight-line approach to this project with what I've learned since I first published it.
Steps 1-3 remain unchanged.
Step 4 is now unnecessary. In the TextMorph's viewer, find the category menu. It's a small 3D-looking label next to the close circle in the upper left corner of each pane of the Viewer.Click it and select the "text" category.Notice that the TextMorph has a property called "numericValue" that has an assignment operator associated with it.We'll use this property in our script in a moment.
We insert a new Step 4, creating a script to be used with all the buttons we're going to include in the Counter. Open the TextMorph's scripts category viewer pane and drag out an empty script object. Now select the numericValue assignment tile by grabbing its large left-pointing arrow and drag it into the script you just created.The tile has a set of up-and-down green arrows on its left. Click on one of these until you see "increase by." Then change the number to the right of that label to "1."
Now for the other bit of magic the Squeak list members showed me. Click on the small dot to the right of the yellow exclamation point in this new script and select "button to fire this script." Voila! A button magically appears that already knows how to trigger the script in question. Just drag it into the Counter and position it. You can, as usual, edit its label and color.
Finally, copy this button twice, place the copies, open their viewers, and change their scripts from "increase by" to "decrease by" for the Decrement button and to a simple assignment to zero for the Reset button.
You're finished.Pretty cool, eh?
If you find problems or issues with this tutorial or just want to chat about Squeak and especially about Morphic, email me.