By Joey Gibson;
corrections and additional chapter on debugging
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:
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
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.
The use of these tools will become more apparent as we work through the tutorial. So, if you're ready, let's move on.
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
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
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
This should present you with a window that looks like this
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,
We now need to create a package for all of our code to go in. To do
this, click on
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 "ManHourCalculator.st" 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
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 (
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
0 MENU ID 1313 1 BEGIN 2 PULLDOWN "Main" 3 BEGIN 4 MENUITEM "About..." ID 1314 5 MENUITEM "Exit" ID 1315 6 END 7 END 8 9 FORM ID 1304 AT (0 0 160 160) 10 NOFRAME 11 NOSAVEBEHIND 12 USABLE 13 MENUID 1313 14 BEGIN 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 18 FIELD ID 1307 AT (89 25 40 12) USABLE LEFTALIGN FONT 0 EDITABLE UNDERLINED SINGLELINE MAXCHARS 10 AUTOSHIFT NUMERIC 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 24 FIELD ID 1312 AT (89 57 40 12) USABLE LEFTALIGN FONT 0 NONEDITABLE UNDERLINED SINGLELINE MAXCHARS 10 AUTOSHIFT 25 END 26 27 FORM ID 1004 AT (2 2 156 156) 28 NOFRAME 29 MODAL 30 NOSAVEBEHIND 31 USABLE 32 BEGIN 33 TITLE "About" 34 BUTTON "OK" ID 1005 AT (56 136 37 13) USABLE LEFTANCHOR FRAME FONT 0 35 LABEL "email@example.com" ID 1008 AT (11 80) USABLE FONT 0 36 LABEL "www.pocketsmalltalk.com" 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.
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.,
PilRC will run, and you should end up with three
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
We first will add constants to the "Resource Databases" category.
To do this, select
Next, we need to add the compiled resources from the last section.
To do this, once again select
After performing these steps you should see something looking like this:
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
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
Now close the Constants browser and re-save your project. We are now ready to start writing code.
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...",
The browser should look like this:
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 "Answer the form to load for this class." ^##MainForm.
This creates a class method called
We will now override a class-side method on the
This is what you should see:
You want to replace "Put your startup code here!" with this:
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
Now we will create our first instance method, which is
initialize "Private - Initialize instance variables." super initialize. hourFieldModel := ValueHolder with: ''. adjustedFieldModel := ValueHolder with: ''. popupListModel := ListModel list: #('Positive' 'Somewhat' 'Not at all'). popupListModel addDependent: self.
We now need to add a method to bind our screen widgets to our application.
This occurs in the
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
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
Once you've accepted and categorized this method, we are ready to
wire up our menu. This occurs in the
createMenus "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
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
hourFieldModel "Answer the model for the number of man hours entered by the user." ^hourFieldModel. popupListModel "Answer the model for the list of sure-ness choices." ^popupListModel. adjustedFieldModel "Answer the model for the adjusted number of man hours." ^adjustedFieldModel.
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.
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:
exit "Stop the Smalltalk VM and return to the Palm apps panel." Smalltalk exit. about "Popup an About... dialog box" Form dialog: ##AboutForm.
The first method is pretty straightforward. Whenever a user clicks
on the "Exit" menu item, the
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." 2 3 | totalHours adjustedHours factor | 4 5 (self widgetNamed: #hourField) updateModel. 6 totalHours := Double fromString: self hourFieldModel value. 7 8 factor := #(1.0 1.5 2.0) at: (popupListModel selectionIndex). 9 10 adjustedFieldModel value: totalHours * factor.
The first thing we do is declare some temporary variables called
The final new instance method we will define is the other half of
a dependency relationship. It is the
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
We will now move on to the final steps before generating our Palm app.
There is one more method from the class
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
Believe it or not, we are ready to generate a
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!
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
To download the ROM from your personal Palm, install the
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,
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
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
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
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
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
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
createComponents "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
To see this in action, build the application using
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
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.
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.
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.