Pocket Smalltalk Tutorial

By Joey Gibson; corrections and additional chapter on debugging
added by Thierry Reignier; updated by N. Chamfort (February 16, 2002).


This tutorial gives a novice Pocket Smalltalk user the necessary information to get moving with PST quickly. I just started with PST a few months ago myself, so I was preparing to write this document while I was learning how to use PST. There is an excellent tutorial that is distributed with the PST package, and I highly recommend that you read it. However, it is the standard "Hello, World!" program that seems to be mandatory for every programming language in existence. It shows you how to get the PST environment running, and then how to create a program with a single button that, when pressed, will popup an alert saying "Hello, World!" What I want to do is take you further than that.

I think you can put most tutorials into three categories:

  1. Those that try to show every component of the system all at once
  2. Those that are based on difficult concepts such as mathematics or computer graphics, and
  3. Those that are so simple as to show you nothing new

The problem with the first group is that it makes it too easy for the novice to get lost. If you are trying to learn a new language or environment, there is a limit to the number of features or components that can be demonstrated in a single application, yet still make sense to the reader. The second group suffers from the fact that the reader may not understand the principles on which the program is based, and will therefore spend an inordinate amount of time trying to understand the "domain" problem, and not enough on the way the system works

A good example of that is the number of books on Java that think a good first example is a class to represent Complex numbers. Math has never been my strong suit, and Complex numbers — with an imaginary part — always seemed wonky to me. Since I had trouble with the underlying "problem", the example was not as effective on me. The third group's problem is that the example is so simple that it doesn't show you how to do anything useful. I hope to avoid all three of these groups' problems.

I will begin by talking a little about the Pocket Smalltalk environment and how to use the development tools. If you already understand this, you can skip ahead. I think it's important to include this information in case this is a new user's first exposure to the system. We will then build a "real" application from start to finish. The application is one that I built from scratch while learning the system, and with this tutorial in mind. It contains text fields, a drop-down listbox, a button, a menu bar, and a menu with a couple of menu items. That sounds like a lot (or not much, depending on your experience), but I think it will provide a good introduction to the system.

Before getting started, you need to ensure that you have all of the necessary tools. The first thing you need is, obviously, Pocket Smalltalk. If you have not already done so, you can obtain it from the Pocket Smalltalk website. The current version of Pocket Smalltalk is 1.6. You will also need to get the Palm resource compiler, PilRC. You can get it from the PilRC website. The current version of PilRC is 2.8. And finally, since we will be doing some double precision math, you will need to get the MathLib kit for the Palm. It is available from the MathLib Information Page. The .prc file in this distribution provide double precision math support for the Palm. You will need to load it onto your Palm, and the Emulator if you use it, for our program to work. (Don't worry, the math I'm talking about is very simple!)

You will also need a tool to unzip the archives that these tools come in. Be sure to use an unzip tool that can deal with long filenames. Unzip all three tools to appropriate locations (I used C:\PocketSmalltalk, C:\PilRC and C:\MathLib, respectively). Once you've installed these tools, you're ready to proceed.


1. Overview of Pocket Smalltalk Tools

The Pocket Smalltalk system, like other Smalltalks, consists of several tools that work together to provide an entire development environment. The tools include a Class Browser, Workspace, Constants Browser, Package Browser and Systrap Browser. The "launcher", the first window displayed upon starting PST is also a tool, since it provides project related services, and access to all of the main tools. Below is a brief description of each of the tools.

Class Browser
The Class Browser is where most of your work will take place. It allows you to browse classes in the system, as well as create your own. You can modify any code in the system, including the system classes! It looks like this:

Class Browser

The top-left pane allows you to see all of the classes in the system, including your own. Right-clicking brings up a context menu with options like Find class... and Make subclass.... The top-right pane shows the methods defined in the class selected in the class pane. Notice it has two tabs, Class and Instance. With the Class tab selected, you will only see those messages that are defined on the class side of a class. The Instance tab only displays those defined on the Instance side of a class. The bottom pane is a multi-purpose pane. It is primarily used for editing methods, but it too is tabbed. The Source tab allows you to edit specific methods of a class. The Class tab shows the definition of a class, which is also editable. The Disassembly tab shows the bytecodes of the selected method, and the Comment tab shows the class comment, if there is one.


The Workspace is a kind of "scratchpad" for testing out Smalltalk code. It looks like this:


You can enter any reasonable Smalltalk expression, or series of expressions, in a workspace, and evaluate it/them, seeing the results. Use the right-click context menu to perform operations on the code you write in a workspace.

Constants Browser

The Constants browser allows you to edit and define constants that are available to classes in the system. Some of the constants are pre-defined, and control aspects of the system. You will create some constants as one of the first steps in our project. It looks like this:

Constants Browser

The top-left pane shows the categories of constants that are currently defined. Clicking on one of these categories populates the top-right pane with all of the constants from that category. Clicking on one of these constants will display the value in the bottom pane, which allows editing. Right-clicking in each of the panes brings up a context menu.

Package Browser

The Package Browser allows you to include "packages" of Smalltalk code into your project. This permits you to include other people's work in your project. It looks like this:

Package Browser

The top pane shows the packages that have been included in the current project. Clicking on one of these packages will populate the bottom pane with information about the classes, methods and constants that exist in the package.

Systrap Browser

The Systrap Browser allows you some level of editing of the traps that integrate with the Palm OS. I currently have no idea how to use this tool, so I won't be covering it here....

The use of these tools will become more apparent as we work through the tutorial. So, if you're ready, let's move on.

2. Setting Up The Packages

The application we will be building in this tutorial is a simple program, but it demonstrates several of the Palm OS widgets. It is simple, but it actually does something. It is called "ManHourCalculator", and computes the number of man-hours a project will "really" take. It is an amusing program that I think will be fun to build, and will help you on your way with PST.

The first step after getting the tools installed is to startup the Pocket Smalltalk system. Either run the pocketst.exe program from a command line, or create a Windows shortcut on your Start menu, and click on that. You should see a window that looks like this

Pocket Smalltalk

This is the main "control center", or "launcher", for the PST system. When you start PST, you are "in" an as-yet-unnamed project. Let's begin by saving it with a name. Click on the System menu, then Save project as..., navigate to the location where you want to keep this project, and name the project file ManHourCalculator.prj. (Henceforth I will use a kind of shorthand for menu commands. The above command would be written as System -> Save project as....)

Now that you've saved the project, we need to add the system packages that we will be using. These packages contain the core Smalltalk classes, as well as the classes that bind to the Palm OS graphic widgets. There are also packages for date/time manipulation and Palm OS database access, but these will be covered in a later tutorial. To open the Package Browser, click on the menu item Tools -> Package browser.

This should present you with a window that looks like this

Package Browser

This tool allows you to import packages of Smalltalk code into your project. There are two packages that we will be including in our project, and To include them, click on Package -> Install package.... You will be presented with a standard Windows file selector. The two packages we want are installed in the top-level directory of Pocket Smalltalk (on my system, this is C:\PocketSmalltalk). First double-click on After a few seconds, while the code in the package is being compiled, the browser should be updated, with "" showing up in the top window. Repeat these steps for After both of these packages have been loaded, we need to tell the system not to update them when we save our project. This is so that changes you make won't propagate to future projects; each project should start off clean. To make this change, right-click on, and select Don't save with project. Do the same thing with

We now need to create a package for all of our code to go in. To do this, click on Package -> New package.... You will be presented with a standard Windows save file dialog. Navigate to your project folder and type in the "File name" text field, and click "Save." You should notice that in the browser's status bar it says "Default:", or whatever you called your package. This means that any new code you write, or constants you define, will be placed in this package automatically.

Note: For some odd reason, version 1.5 of Pocket Smalltalk does not retain the default package setting between invocations. You must remember to re-set the default package to your "" package each time you start PST. To do this, open the package browser, right-click on your package, and select "Set as default" from the context menu. Failure to do this will result in methods being "lost" between sessions.

Now is a good time to save your project again. Close the package browser and then click on System -> Save project on the launcher. It is a good idea to save your project frequently to prevent loss of work.

3. Creating The Resources

The next step doesn't involve the PST development tools at all. Unlike Java or other Smalltalk systems where the graphic widgets are implemented in native Win32 code, PST uses a different approach. Since the widgets are part of the Palm OS, we use those, and just bind our code to them. We have to create a resource recipe file (.rcp) which defines our forms and the widgets that live on them. To create this resource file, use any plain-text editor.

Actually, a better way is to use a builder tool. There are currently two choices: PilotMag and ThTkBuilder. PilotMag is what I used to create the resource file for this project. It is a payware program, but well worth it. You can graphically layout your forms, menus and whatnot, and have it generate the resource file. It was designed to work with the GCC for Palm C/C++ compiler, so is geared for C/C++ development, but is very useful just for the GUI builder. ThTkBuilder is another version of PST that contains a built-in GUI builder. ThTkBuilder is still an alpha product, but it looks extremely promising. In addition to generating the resource file, ThTkBuilder will write a fair amount of the binding code that I will be demonstrating later on for you.

Below is the full text of the resource file. You should type this into your editor and save it in your project directory as ManHourCalculator.rcp. (Don't type the numbers at the beginning of the lines; those are for reference in the rest of this section.)

 0  MENU ID 1313
 2      PULLDOWN "Main"
 3      BEGIN
 4          MENUITEM "About..." ID 1314
 5          MENUITEM "Exit" ID 1315 
 6      END
 7  END
 9  FORM ID 1304 AT (0 0 160 160)
13  MENUID 1313
15      TITLE "ManHour Calculator"
16      BUTTON "Calculate" ID 1305 AT (50 138 53 13) USABLE LEFTANCHOR FRAME FONT 0
17      LABEL "How many hours?" ID 1306 AT (2 25) USABLE FONT 0
19      LABEL "Hour sure are you?" ID 1308 AT (2 41) USABLE FONT 0
20      POPUPTRIGGER "Positive" ID 1309 AT (89 41 51 12) USABLE LEFTANCHOR FONT 0
21      POPUPLIST ID 1309 1310
22      LIST "List1" ID 1310 AT (89 41 65 33) NONUSABLE DISABLED VISIBLEITEMS 3 FONT 0
23      LABEL "Adjusted Hours" ID 1311 AT (2 57) USABLE FONT 0
25  END
27  FORM ID 1004 AT (2 2 156 156)
33      TITLE "About"
34      BUTTON "OK" ID 1005 AT (56 136 37 13) USABLE LEFTANCHOR FRAME FONT 0
35      LABEL "" ID 1008 AT (11 80) USABLE FONT 0
36      LABEL "" ID 1009 AT (10 107) USABLE FONT 0
37      LABEL "Home:" ID 1010 AT (11 97) USABLE FONT 1
38      LABEL "Mail:" ID 1011 AT (11 68) USABLE FONT 1
39      LABEL "ManHour Calculator" ID 1320 AT (39 23) USABLE FONT 0
40  END

If you're lazy and don't feel like typing it in, you can download it here.

The purpose of this file is to declare the widgets that will show up on our forms, declare the forms themselves, the menus and whatnot, and to place the widgets. Let's look at the file so you will understand what it does. We won't go over every line, just some of the highlights.

Line 0
This line declares a menubar that will have one or more pulldown menus. The ID 1313 clause gives the menubar a number, or ID, that we will use later to bind it into our code.
Lines 2 - 6
The PULLDOWN and the MENUITEM keywords create, of all things, a pulldown menu called "Main", and two menu items called "About...", and "Exit".
Line 9
This line creates a form, the fundamental GUI widget, with an ID of 1304, and places it on the Palm screen, covering the entire thing. (The Palm screen is 160x160 pixels.)
Lines 10 - 12
These are options that control how the form looks and works.
Line 13
This line binds the menu created earlier with this form. This line causes the menu we created to show up when the user clicks on the menu button on the Palm, when this form is displayed.
Line 15
This is the text that will appear at the top of the form on the Palm.
Line 16
This creates a push button with the text of "Calculate" on it, and places it at the coordinates in parentheses. The ID is 1305, which we will later use to bind code to the button.
Line 17
This line, as well as all the lines beginning with LABEL create static text labels at the specified coordinates.
Line 18
This create a text field that only accepts numeric input.
Lines 20 - 22
Unlike other languages where you create a drop-down listbox by instantiating one widget, here you have to create a "trigger" and the list itself. The trigger is created on line 20, and the list on line 22. These are tied together by line 21.
Line 24
This line creates a textfield that does not accept user input. We will use it to show the user the result of our calculation.
Line 27 - 40
These lines create another form, that we will use for our About box.

Once this file is created, you need to compile the resources. This is where PilRC comes in. To run PilRC, open a DOS command line window, change into your project directory (e.g., cd c:\PocketSmalltalk\), and execute this command:

    pilrc ManHourCalculator.rcp 

PilRC will run, and you should end up with three .bin files that contain resources. These are compiled representations of the widgets you specified in the resource file. Now that we've got our resources compiled, we can go back into PST to start the process of binding them to code.

4. Defining The Constants

It is now necessary to create a few constants that link some system resources into our project. We will also change a few previously defined constants to represent data specific to our project, and we will create constants for each graphic widget so that we can refer to named constants instead of the ID numbers defined in the resource file.

Open the Constants browser by clicking on Tools -> Constants browser in the main PST window. The constants are listed in categories which are named in the left-hand pane. Clicking on a category will populate the right-hand pane with the constants defined in that category. Clicking on one of the constants will put the value of the constant in the bottom editor pane. Changes to the value must be accepted by selecting "Accept" from the context menu, or pressing Ctrl-S.

We first will add constants to the "Resource Databases" category. To do this, select Constants -> Add resource database.... You will be presented with a standard Windows file dialog. The first resource database we will add is the main virtual machine. It is a file called vm-math.prc, and it is located in the main PST install directory. (There is also a vm.prc that you should use if you don't need to do calculations on double values.)

Next, we need to add the compiled resources from the last section. To do this, once again select Constants -> Add resource database..., and navigate to your project directory. Click on the "Files of type" drop-down list at the bottom and select "PalmOS Resources (*.bin)". You should then see the three .bin files that were generated by the resource compiler. Double-click on any of these. The full path to this file will be placed in the editor pane of the browser. You should select the filename part of it, and change it to a "*". For example, if the editor shows 'C:\PocketSmalltalk\ManHourCalculator\tFRM0518.bin', replace "tFRM0518" with "*". This will import all files that end in .bin. Otherwise you would have to create a constant for each file. Accept your change by typing Ctrl-S.

After performing these steps you should see something looking like this:

Constants Browser

We will now create a category of constants called "Widgets", which will contain constants for the graphic widgets we created in our resource file. To do this, right-click in the left-hand pane and select "Add category...". In the box that you are presented with, type Widgets and hit the OK button. Now right-click in the right-hand pane and select "New constant...". In the box that pops up, type in MainMenu and press OK. You will notice that there is an entry in the right-hand pane that says "##Mainmenu", and the editor pane says "nil." Select "nil" in the editor, and change it to 1313. Then accept the change. You need to do this for each of the widgets we created in our resource file. Here is what I used:

	MainMenu            1313
	AboutMenuItem       1314
	ExitMenuItem        1315
	MainForm            1304
	CalcButton          1305
	HourField           1307
	PopupTrigger        1309
	PopupList           1310
	AdjustedField       1312
	AboutForm           1004

You can create constants for the labels in our application, but there is no reason to do this unless you need to reference one of them directly. Having them defined in the resource file is enough to make them show up on the Palm screen.

We will now change one of the system constants to make it specific to our project. Click on the "System Properties" category, then click on the ##applicationTitle constant. Change "Smalltalk App" to "ManHour Calc". This will be the name that shows up in the Palm application launcher once we load our completed program. Accept your change, and then right-click on the constant in the right-hand pane. From the context menu, select "Change package...". A window will open displaying all of the packages in this project. Select "" and press the OK button. This will cause our version of the constant to be saved in our custom package.

Now close the Constants browser and re-save your project. We are now ready to start writing code.

5. Writing Code: The Class and Class-Side Methods

Now that the setup work is complete, we are now ready to begin writing actual code! The first thing we need to do is create an application class. We will be subclassing off of Application. To do this, open a class browser, and select the "Application" class in the left-hand pane. Once you've selected this class, right-click on it, select "Make subclass...", and type ManHourCalculator in the resulting box. If you did this correctly, you should see that the tree for Application has expanded, and our new "ManHourCalculator" class is under it.

The browser should look like this:

Class Browser

If your class appears anywhere else in the tree, you did not have Application selected when you created a subclass. You can correct this by clicking on your "ManHourCalculator" class, clicking on the "Class" tab. Then change the first word from whatever it is (probably Object) to Application, and accept the change.

Before we start defining methods, we need a few instance variables to hold the values of our widgets. (In a "real" application you would most likely have an entire class that represents your data model. However, to simplify this application we will be using instance variables within our main application. This will probably give some true OO people heartburn, but I really wanted to make certain that the details didn't get too complicated.) Click on the "Class" tab in the editor pane; you should then see the definition of our class. To make it easier for you to declare the instance variables, I've just copied the entire class definition below:

Application subclass: #ManHourCalculator
    instanceVariableNames: 'popupListModel hourFieldModel adjustedFieldModel'
    classVariableNames: ''
These three variables will be holding objects that hold values for our widgets. We will be creating those in a minute.

The first method we will define is the class method formID. (From now on I will use standard Smalltalk shorthand for methods: class methods will look like this ManHourCalculator class>>formID, and instance methods will look like this ManHourCalculator>>initialize.) To create a class method, click on the "Class" tab of the right-hand pane, right-click inside it, and select "New method." It would appear as if nothing has happened, but the editor pane is now ready for you to enter a complete method definition. Type and accept the following code exactly as shown:

    "Answer the form to load for this class."

This creates a class method called formID that returns the constant for the main form of our application. If you typed this correctly, then pressing Ctrl-S should cause a method name, formID, to show up in the right-hand pane. That is the only class side method that we will be defining.

We will now override a class-side method on the Smalltalk class. The method in question is Smalltalk class>>start, and it is what will cause our application to startup when you click on it on your Palm. To do this, find the class Smalltalk in the left-hand pane of the class browser, select it, then click on the "Class" tab in the right-hand side. Click on the plus sign next to "startup", and then click on "start."

This is what you should see:

Class Browser

You want to replace "Put your startup code here!" with this:

    ManHourCalculator show.

Accept your changes. There is one more step with this method that must be taken. If we were to leave things as they are now, then when you exit PST, and restart, your redefinition of Smalltalk class>>start would be gone. This is because we told the environment not to save changes to the core package, and we didn't say where we wanted our new version to live. That's what we need to do now. To do this, right-click on the start method in the right-hand pane, and select "Change package...". Your "" package should already be selected in the resulting dialog box, so click on "OK." Now when you come back into PST, this change will still be there. We have to do something similar for an instance method on the "Application" class, but we will save this for later.

6. Writing Code: Instance Methods

Now we will create our first instance method, which is ManHourCalculator>>initialize. Select our "ManHourCalculator" class in the class pane (the left-hand pane) of the class browser, then click on the "Instance" tab on the right-hand pane. Select "New method" from the context menu and enter the following in the editor pane:

    "Private - Initialize instance variables."
    super initialize.
    hourFieldModel := ValueHolder with: ''.
    adjustedFieldModel := ValueHolder with: ''.
    popupListModel := ListModel list: #('Positive' 'Somewhat' 'Not at all').
    popupListModel addDependent: self.

The initialize method will be called when an instance of the class is created. In this method we initialize our instance variables with ValueHolders. These object can hold another object, and respond to the value and value: methods. They can also send messages when the value they hold changes. As I said earlier, in a real application, we would be using another class as our model. If this were the case, then the ValueHolders would be wired to an instance of that class. Since I was going for simplicity in this tutorial, the ValueHolders will be our model. The final line sets up a dependency relationship that will cause a method to be called when the popuplist's value changes. More on this later.

We now need to add a method to bind our screen widgets to our application. This occurs in the createComponents method. Here is the definition for ManHourCalculator>>createComponents:

    "Bind the screen widgets to our application code."
    super createComponents.
    self add: Button id: ##CalcButton name: nil aspect: #calcButtonPressed.
    self add: TextField id: ##HourField name: #hourField aspect: #hourFieldModel.
    self add: TextField id: ##AdjustedField name: nil aspect: #adjustedFieldModel.	
    self add: Listbox id: ##PopupList name: nil aspect: #popupListModel.

This code does several things. First, we call the createComponents method of our superclass, in this case Application. For Application this doesn't actually do anything, but it is always a good idea to call the superclass' version of an overridden method to make certain that your object gets all of the proper behavior. The next four lines setup the bindings between the components that will show up on the Palm screen, and our application. The add:id:name:aspect: method does this for us. The first argument is the type of widget we are adding. (There are classes that map to each type of screen widget, and these are scattered under the hierarchy of class Model.) The second argument is the widget ID that we assigned in our resource file. Here we are using the constants that we defined in our "Widgets" constant category. The third parameter creates a name for the component that we can reference later on. We don't need a name for the button since it will be an active component (meaning it will call our code), but the text field called #hourField will be referenced from within our code. The final parameter is truly the "glue" between the widgets and the code. The aspect is the name of a method on our class that is called by the widgets. For the button, this is the method called when the user clicks on it. For the textfields and the listbox, this method will return a reference to the model for the caller. For those it is the ValueHolders we created earlier.

It is always a good idea to categorize your methods. For some methods, the browser will automatically assign a new method to what it thinks is the best category. If it doesn't put a method where your think it should go, you can right-click on a method and select either "Quick categorize..." or "Categorize...". The first presents you with a list of common categories, while the second allows you to type in a new category. The categories are just for organization, but they help when trying to find a method. Methods like createComponents and initialize could go into the initializing category.

Once you've accepted and categorized this method, we are ready to wire up our menu. This occurs in the createMenus method. With the "Instance" tab selected for our "ManHourCalculator" class, right-click in the list of methods, and select "New method...". Here's the code:

    "Wire up our menus to the code."
    super createMenus.
    self addMenuAction: #about forID: ##AboutMenuItem.
    self addMenuAction: #exit forID: ##ExitMenuItem.

This method performs a similar function to that of createComponents, but the syntax is a bit different. Again, we call our superclass's method to get whatever behavior is provided there. We then setup our two menu items to do their thing. The addMenuAction:forID: method says that for a given ID, call a certain method. The first one binds the ManHourCalculator>>about method to the menuitem whose ID is the value of the constant ##AboutMenuItem. The second sets up the binding between the menu item identified by the constant ##ExitMenuItem and the method ManHourCalculator>>exit. We will define these methods in a minute. Now accept the method, and make sure it is in the "initialization" category.

We will now define the methods that will live in the "aspects" category. (There is no default category called aspects, so after creating one of these methods, select "Categorize..." from the context menu and enter "aspects" for the category name.) There are three methods, and these correspond to our two textfields, and the list that we setup in createComponents. Right-click in the method list and select "New method..." for each of the following methods. (Be sure to accept each method when you're done with it.)

    "Answer the model for the number of man hours entered by the user."

    "Answer the model for the list of sure-ness choices."

    "Answer the model for the adjusted number of man hours."

These methods are attach the screen widgets to our model. Each one should return the object that will hold the value for a particular widget. Since we are using ValueHolders as our model, the code for each of these methods is quite simple. I'm not totally certain what piece of the system calls these, but they are required, so include them.

7. Writing Code: Instance Methods (Actions)

We will now create the three methods that are called by the button and the menu items that we created earlier. There is no default category for actions, but after you have created one of the methods, you can select "Categorize..." from the context menu and enter "actions" as the category name. Again, to create these methods, right-click in the instance methods list for our "ManHourCalculator" class, and select "New method...". Then enter and accept the code in the editor. Here are the first two methods:

    "Stop the Smalltalk VM and return to the Palm apps panel."
    Smalltalk exit.
    "Popup an About... dialog box"
    Form dialog: ##AboutForm.

The first method is pretty straightforward. Whenever a user clicks on the "Exit" menu item, the #exit method is called, which just tells the Smalltalk virtual machine to exit. The second method calls a class-side method of the Form class, dialog:, passing it the resource ID of our aboutForm. This causes the form to display modally, returning to our main screen when the user clicks on the OK button.

The final "actions" method is the aspect for our button widget. This is the most involved method in our application. Here is the code (don't enter the line numbers!):

 0 calcButtonPressed
 1    "Compute the actual number of man-hours to complete a task."
 3    | totalHours adjustedHours factor |
 5    (self widgetNamed: #hourField) updateModel.
 6    totalHours := Double fromString: self hourFieldModel value.
 8    factor := #(1.0 1.5 2.0) at: (popupListModel selectionIndex).
10    adjustedFieldModel value: totalHours * factor.

The first thing we do is declare some temporary variables called totalHours, adjustedHours and factor. These will be used in our computations. Line 5 gets a reference to the screen widget called #hourField and tells it to update its model, which puts the value the user entered into the #hourFieldModel ValueHolder. Once that is done, line 6 gets the new value from that model by calling the value method. Line 8 asks the popupListModel which of its items the user clicked on. This returns an integer index, which we then use to pull a multiplier out of a literal array. This value is then assigned to the temporary variable called factor. If the user selected "Positive", then we will multiply the number of hours they entered in the #hourField widget by 1.0 (no change) , as the actual number of hours the project will take. If the user selected "Somewhat," then we will multiply the hours the user entered by 1.5. And if the user selected "Not at all", then we will multiply by 2.0. (Amusing, no?) The final step is to update the model for the #adjustedField textfield so that the "actual" hours for our project will appear in the proper field on the screen. Line 10 does this by multiplying the totalHours variable by the factor, and storing that value in the adjustedFieldModel ValueHolder. By using a ValueHolder for each model, all we have to do is call the value: method and the widget will get and display the new value.

The final new instance method we will define is the other half of a dependency relationship. It is the update:with:from:. It lives in the "dependents" category and it looks like this:

update: anAspect with: aValue from: anObject
    "Triggered from a model that we asked to send us updates."
    anObject = popupListModel
        ifTrue: [self calcButtonPressed].

This method will be called when the user clicks on the popup list of choices, and makes a selection. When this method is invoked, we first need to make sure that it came from the component we think it did. Since we only asked one model for updates, the test isn't strictly necessary. If we had asked for updates from several models, then we would need to differentiate each call of this method to determine which action to take. In our case, assuming the invocation came from the popup list model, we will call the #calcButtonPressed method. The application will behave as if the user had clicked on the button, and will compute the new hours. The update:with:from: method in this application is not totally necessary, but I wanted to at least show it. The dependency mechanism in Smalltalk is an incredibly powerful tool.

We will now move on to the final steps before generating our Palm app.

8. Final Steps

There is one more method from the class Application that we need to override. This method is called #handlePopupSelectEvent, and it causes changes in the popup list to change the label of the popup trigger, so that the item selected in the list will be displayed after the list is hidden. Click on the Application class in the left-hand pane, click on the plus sign next to "event handling" in the "Instance" tab on thr right, and then click on the "handlePopSelectEvent" method. Now change the last line from ^true to ^false.

Class Browser

If you don't make this change then making a selection in the popup list, while it will update the mode, will not change the trigger label. Just as with the #start method, we need to move our version of this method to our package. After making the change and accepting the method, right-click on its name and selected "Change package..." and select our "" package.

Believe it or not, we are ready to generate a PRC file that can be loaded onto your Palm (or the Palm emulator as you will see in the next section). After saving your project again (you have been saving your project frequently, haven't you?), select System -> Generate code. You will be presented with a standard Windows file dialog box. Navigate to your project directory and type ManHourCalculator into the File Name box, and click on the "Save" button. You should end up with a file called "ManHourCalculator.prc" in that directory, that is somewhere around 57 kilobytes in size.

Now comes the real test: does it actually work? Odds are that even if you've been following this tutorial closely, you've still made a mistake somewhere. I did as I was writing the thing! Don't worry about it; experience will help you as you become more familiar with PST. So, let's try to run it!

9. Running Under POSE

POSE is the Palm OS Emulator, and it is available from the Palm Computing Developer Zone. It was originally created by Greg Hewgill and was then tacken over by Palm Computing. Once you've downloaded and installed it, what you have is an emulator that can't do anything yet. You need a ROM for it to use. There are two ways to get a ROM. If you are a Palm owner, the emulator comes with a PRC file that will download your ROM to a file that can be used with POSE. The benefit to getting your ROM this way is that the emulator will be running exactly what your Palm is. This makes it a really good testbed. The other way is to download a debug ROM from Palm Computing. There is a license agreement you have to accept, but I don't believe it is anything earth-shattering. I've not read it, since I have a Palm V, but I know others have used that route to get a ROM.

To download the ROM from your personal Palm, install the Transfer.prc file from the POSE distribution onto your Palm. Then run the emulator, and select the "Download ROM" option. Follow the directions on downloading that pop up. Once you've completed this step, go through the setup of POSE to customize it for your setup. Mine is a Palm V, with 2Mb of memory. Once you get it setup and started, you should an image of a Palm on your screen with a display like the image below. Depending upon the OS version you're running the applications may be slightly different, but most of it should be the same.


In order to test our application, we need to install it on the emulator. But first, we need to install the MathLib.prc file. Without this loaded, our application won't work. To install it, right-click on the emulator, select Install Application/Database... and then navigate to wherever you put the MathLib package. Double-click on the MathLib.prc file to install it. Now right-click anywhere on the POSE window, select the Install Application/Database menu item, and then the Other... menu item. Navigate to your project directory and double-click on your ManHourCalculator.prc file. You will see a progress meter during the load, and then it will look like nothing happened. Sometimes the display does not refresh itself properly, and you need to force a repaint. To do this, click on the "Address Book" icon, or one of the others, then click on the Application silk-screen button to return to the main apps page.

You should now see a new icon for our app, with the name set to "ManHour...". Click on this, and you should see the following screen:


If you get something different, you've made a mistake. If you saw a flash, and were then returned to the apps panel, you probably forgot to override the Smalltalk class>>start method. If you got some odd error message, and then a debug walkback, you probably have some sort of error in error in ManHourCalculator>>initialize, ManHourCalcualtor>>createComponents or ManHourCalcualtor>>createMenus. Go back and look at your code in the class browser and verify it against the previous sections of this tutorial and then come back here.

If you see the screen above, then you are in good shape so far. Click on the text field next to the label "How many hours?" label and then type in 20. (Of course, if you are actually running this on a Palm, you would graffiti the numbers instead of typing.) Now click on the "Calculate" button. What happened? Did you get the value 20.0000 in the "Adjusted Hours" field like this:


No? Then what sort of error message did you get? Your problem most likely lies in the ManHourCalculator>>calcButtonPressed method. Again, compare your version to that in the previous sections. If you got the answer 20.0000, then try clicking on the popup list next to the "How sure are you?" label, and select "Somewhat."


You should see 30.0000 appear as the adjusted hours.


And if you select "Not at all", you should see 40.0000 as the adjusted hours. If any of these fail, go back and look at your calcButtonPressed method.

Now let's try out our menu. Press the menu key


and you should see the menu popup at the top of the screen:


You should get the About box that we defined in our resource file. It should look something like this:


Click on the OK button to return to our main form. Selecting Exit from the menu will return you to the Palm applications screen.

When exiting from the application, you may see this error message if you are using a debug ROM:

If this error appears, donŐt worry, it's just that PST doesn't always correctly release some memory when using the debug ROM.

If all of this has worked, congratulations! You have just written and tested your first Pocket Smalltalk application. You can take that same PRC file (and the MathLib.prc file) and install it on your Palm using the Palm Desktop installer and show it to your friends.

10. Using the Debugger

Pocket Smalltalk also includes a simple debugger for looking at the execution stack, the value of parameters passed with messages, and temporary variables. To see the debugger in action, we can modify the ManHourCalculator application as follows:

Modify (well, break it intentionally) the method definition for ManHourCalculator>>createComponents (see the bold text)

    "Bind the screen widgets to our application code."
    super createComponents.
    self add: Button id: ##CalcButton name: nil aspect: #calcButtonPresseded.
    self add: TextField id: ##HourField name: #hourField aspect: #hourFieldModel.
    self add: TextField id: ##AdjustedField name: nil aspect: #adjustedFieldModel.	
    self add: Listbox id: ##PopupList name: nil aspect: #popupListModel.

This modification will cause a "Message not understood" error, because the method #calcButtonPresseded does not exist.

To see this in action, build the application using System -> Generate code, and then re-install the ManHourCalulator.prc file on your device or emulator. Start the application as described before, and click on the Calculate button.

PST now enters the debugger and raises the following notification error:

The application enters the debugger to help you solve the problem. Note that before actually seeing the debugger you will receive this error message if you are using the emulator.

Don't worry, just press Continue. You will have to do this 3 more times, until the debugger takes control:

The upper list shows methods on the stack in decreasing order. Press the arrows to browse up and down the execution stack.

If you select a method you can then view its associated parameters and temporary variables. Parameters and method temporaries are shown in the same list, with parameters displayed first. The symbols for the parameter and variable names are not preserved, so you may need to look at the method source code to understand all the values shown in the debugger.

Use the Done button to exit the debugger, and the Memory button to display the current amount of PST and Palm memory availsble to your application.

11. Wrap Up

Well, we made it. I hope that this tutorial has been useful and that you will go on to write many useful applications using Pocket Smalltalk. If you found this document helpful, I would really appreciate an email telling me what you thought of it. I welcome all comments, both good and bad. Let me know anything that you think was good, but also anything that you believe is wrong. As I said in the introduction, I've only been using PST for a couple of months myself, so there is the chance that something I said was wrong. The application can be built using the instructions I gave, but perhaps something could have been done better. I need to know this, too. Send feedback/comments/suggestions to Joey Gibson and I promise to read and answer them.

12. References

Below is a list of the URLs that were discussed throughout the tutorial for easy reference.

Copyright © 2000-2002 Joey Gibson

Last updated: Feb 16, 2002

Palm Powered is a trademark of Palm Inc. Pocket Smalltalk is trademark of Pocket Smalltalk Group. Copyright (c) 1998 - 2002 Pocket Smalltalk Group.