Resources, forms and controls
By Alan Jay Weiner
Last month, we walked through a "simple" "hello, world" application. While we covered the code in almost tedious, thorough detail, I glossed over the resources somewhat. Resources are as important as the code itself; they're intricately entwined together. So this month we'll look at resources, forms, and controls. Grab a cup of coffee and let's begin!
What are resources?
Resources are "things" that a program can use. A resource could be as simple as a text string or as complicated as a screen form with menus, buttons, fields, and other resource "things." Forms and controls are types of resources.
Resources are essentially data structures tacked onto the end of the program file. Some Palm OS APIs expect to use certain resources; others you use by requesting a pointer and using the data at that address. For example, you might want to display a bitmap with your company logo. With the bitmap attached as a resource, you'd get a pointer to it by calling DmGet1Resource(), then display the bitmap by calling WinDrawBitmap(). Attaching the bitmap as a resource saves you from using up precious limited data and program space. While the resource could simply be in a separate data file, attaching them to the program is convenient - they're always there when you need them.
Resources can also be modified without changing the program itself. For example, if an application's text messages are all resources, changing the messages to a different language involves just using a different set of resources, rather than recompiling the program.
Some resources can refer to other resources. For example, a form resource is built out of a collection of control resources (buttons, fields, lists, etc.). Rather than using each resource individually, you'd simply say "display the form" and the OS's form-displayer knows to display all the other resources. That form might also have a "help" message which would point to a string resource. When the user hits the "i" on the menu bar, the form handler automatically displays the string resource.
After the program is compiled and linked, another tool builds the necessary data structures from a description of the resources, then attaches those structures to the program file. The program carries the resources on its back like a camper with a backpack full of supplies.
"Hello world" only used a few resources. It uses a couple of forms, a couple of menus, and a bitmap. Most programs use many more. In fact, even the program's code and data are stored as resources; the .PRC file is a header structure followed by everything else as various resources.
Resources are just data structures
For the most part, we don't care about the resource's structure itself; just what capabilities that resource has, how we refer to the resource, and what we can do with it. String resources are just that: a text string. We can request a pointer to the string, and we can use the string (referenced via that pointer) or we can reference the string by another resource (as the 'help' message for a form, for example). Form resources are far more complex, but we simply refer to them by their identification number; we would call FrmGotoForm(1000) to go to form number 1000.
Each resource is identified by a resource type and an identification number. Palm has defined a number of resource types. Some of these will already be familiar to Macintosh programmers. Each resource type is a four-character name; the string resource above is 'tSTR'. The resource-development tools handle all the name issues for us, but it's useful to be familiar with them; occasionally you'll see reference to "a Talt" or "a tAIN" resource. The sidebar "Resource Types" lists many of the common resource types.
Forms are a collection of resources
Each of the controls on a form can be a resource by itself, but when they're built into a form, they become an integral part of the data structure defining that form. The form data structure contains information about the form itself (such things as height and width); the data structure for each control is concatenated to the form's structure.
Other resources, such as the help message or the form's menu, are separate resources within the application file but are referenced from the form's data structure. This all happens automatically. You don't need to do anything special to make this happen. You simply build a form using the appropriate tools for your development environment. The tools build the right structures.
CodeWarrior and GCC use different tools to build resources.
CodeWarrior provides a graphical utility called "Constructor" while GCC uses a text script and the PilRC utility. Unfortunately, there's no easy way to convert from one to the other. If you have a program written using one compiler, it's pretty easy to compile it using the other, but the resources need to be recreated manually.
Building resources with CodeWarrior's
While a complete tutorial on Constructor is beyond the scope of this column, the basics are described here.
You open a resource "project" which shows a list of the various resources for that application. Figure A shows the resource project for the "hello world" application. This project is different than the CodeWarrior IDE (Interactive Development Environment) project; the IDE project file uses an .MCP extension while the resource project is a .RSRC extension. The .RSRC file will be included in the IDE's project as a dependent file.
Constructor displays the .RSRC file as a list of resources.
Figure B shows the application's main form. The left pane shows the form's information. Simply click on a field to change it.
The form resource. The left pane shows the form's parameters.
As the form is changed, the right pane displays the form's image. To place a control (i.e., a button) drag it from Constructor's "catalog" window, as shown in Figure C, and drop it onto the form.
The "catalog" of controls; drag-and-drop these onto forms.
Selecting a control by dropping it onto the form or by clicking on an existing control allows you to edit the control's data. Figure D shows the form with the label control selected. The left pane shows the label's data.
The same form resource as in Figure 2, after clicking on the "hello world" label.
There are several glitches with Constructor, at least on the Windows version. These will likely be fixed in future releases, but I'll list them here to save you some hair-pulling.
First, Constructor creates two .RSRC files: the first is a zero-length file, the second is in the Resource.frk directory beneath it. That second file is the one with the real information in it, but the IDE project should include the first (zero-length) file. If you accidentally include the lower file, you'll get problems with linking. This is an anomaly due to the tools Metrowerks uses; the tools allow them to create both a Macintosh and Windows version. It's odd, ugly, and the way things are. Just mentally ignore the copy in Resource.frk (the one with the actual data) and always refer to the zero-length file. If you have problems opening a resource project you may be opening the wrong one.
Second, no you can't double-click on the resource file in the IDE and open up Constructor (as you would double-click on a source file to edit it). You need to start Constructor and select Open Project File from the File menu. Be sure to open the upper (zero-length) .RSRC file - Constructor knows to open the real one beneath it.
Third, creating an image using Windows Paint and cut-and-pasting it into a bitmap resource in Constructor will sometimes fail. When it does, you'll see the image, but as if it's been shifted horizontally. If this happens, change the Paint settings so you're creating a color bitmap. Then you should be able to cut-and-paste it successfully.
Despite these problems, Constructor is convenient and fairly easy to use.
Building resources with GCC (PilRC)
GCC uses the PilRC utility to compile a text script into the resource data structures. You describe each resource with a series of commands.
Listing 1 (below) shows the resource script for the "Hello World" application. The line starting with "LABEL" describes the same label displayed in Figure D.
The ID numbers are defined in the include file "hello.h"
One major advantage to PilRC is that this script is easily printed. It would be quite difficult to describe the Constructor-built resources in human-readable terms.
The user interface is mostly resources
Most of an application's user interface will be built using resources. The "Hello World" application's user interface consisted of two forms. Each form contained some text and a control or two. The main form used a menu resource. Only the "hello again" message was explicitly drawn; the rest of it all was resources.
Since forms are the basis for almost all the user interface, let's finish this month with a detailed look at the main form resource.
The form resource in detail
A form has various attributes, such as its position (if smaller than full-screen), its height, width, and so on. As mentioned before, it can contain control resources within it, and may use certain other resources like a string resource as the help text, and a menu resource.
Looking again at Figure B (which we've redisplayed below), we see the main form as built in Constructor. This corresponds to the lines between "FORM ID MainForm" and "END" in Listing 1.
The main form built in Constructor.
The attributes of the form are shown in the left pane. Each element may be edited by clicking on the value and typing in a new value. These are the elements in the form's data structure itself; the control resources will be tacked on following this data. We don't need to worry about the actual structure layout. That's all handled by Constructor.
The left and top origin define the screen coordinate where the top-left corner of the form is placed. The physical screen is 160 pixels across and 160 pixels tall. The origin coordinates range from zero to 159. (0,0) is the top left of the screen.
The width and height define the size of the form in pixels. A full-screen form is 160 by 160. The main form of Hello World uses the full screen.
Most controls have a "usable" attribute. If it is not usable, it will not be drawn when the rest of the form is displayed. Since forms aren't drawn until you explicitly switch to the form, they will always be marked "usable."
"Modal" indicates whether the form's event handler should deal with pen events outside the form. A modal form will ignore any pen-taps outside itself. Modal forms also have a border - it's drawn by the form displayer during the FrmDrawForm call. You might want to refer back to April's Programming Power column to review the form-open events.
"Save Behind" tells Palm OS to save the portion of the screen which will be obscured by this form when it draws the form. When the form is closed, Palm OS will automatically restore that part of the screen. I've had odd results with this at times; sometimes things underneath the form show through when the form is first drawn. When that happens, typically setting "save behind" will fix it, even though "save behind" should cause things the other way around. It should leave garbage when the form is closed rather than mess it up when it's first drawn.
"Form ID" is the resource's identification number. Remember when I said resources have a type and an ID? This is the ID. The type is 'tFRM' by the way.
Constructor can create a header file with these IDs. See Listing 1; near the bottom where it says "header file name" and "auto generate header file" is checked; this tells Constructor to write all the IDs in a file called HelloRsc.H. In this case, the form name will be MainForm.
"Help ID" isn't used in this particular form. That's why it's greyed out. If we wanted a help message for this form, we would make the ID a number other than zero, and we would define a string resource with the text. The Create button is a convenience; we could also go to the project window, click on "strings" and then create a new string by selecting New String Resource from the Edit menu command.
When a form has help text, the form displayer automatically makes the menu bar the full width of the form, and puts the "i" button at the right.
"Menu bar" indicates the identification number of the menu resource. Like Create for the help ID, the Edit button is a convenience. If the menu resource hasn't been created, the edit button will be a Create button.
When the system closes a form automatically, as it would when it switches to another application, it will simulate pressing the "Default button ID" button. In this case, there is no default button.
Finally, the "form title" is just that: the title shown on the menu bar. The "hex" button displays the title text as hex values. This is convenient when using non-alphanumeric characters.
Looking at Listing 1, you can see how PilRC uses similar terminology to define the form. "FORM ID MainForm AT (0 0 160 160)" indicates the top and left origins and the height and width. "MENUID MainFormMenuBar" indicates the ID number of the menu resource, which is defined a few lines later.
Now that we've finished our coffee (and in a few cases, the whole pot!) we'll tie things off here. Next month we'll look at some of the user-interface controls; what they do and how to use them.
Each resource is identified by a type and an ID number, as shown in Table A. These are some of the common types; you'll occasionally see them mentioned in articles or newsgroup and maillist messages. For the most part, you won't deal with the type codes; you'll just deal with a resource of a particular variety. The type codes are case-sensitive.
TABLE A: Typical PalmPilot Resource Codes
#include "hello.h" FORM ID MainForm AT ( 0 0 160 160 ) NOFRAME USABLE MENUID MainFormMenuBar BEGIN TITLE "Hello" LABEL "Hello World!" ID MainHelloWorldLabel AT (49 40) FONT 2 BUTTON "hello again" ID MainHelloAgainButton AT ( 46 129 68 14) USABLE FRAME FONT 0 END VERSION 1 "1.0" ICON "hello.bmp" MENU ID MainFormMenuBar BEGIN PULLDOWN "Options" BEGIN MENUITEM "About" MainOptionsAbout END END FORM ID AboutForm AT ( 2 18 156 140 ) FRAME MODAL USABLE MENUID MainFormMenuBar BEGIN TITLE "About" LABEL "Hello World" ID AboutAppNameLabel AT (51 22) FONT 1 LABEL "Version 1.0" ID AboutVersionLabel AT (52 32) FONT 1 LABEL "PalmPower Magazine" ID AboutAuthorLabel AT (4 50) FONT 0 LABEL "April 1998" ID AboutAuthorLabel+1 AT (PREVLEFT PREVBOTTOM) FONT 0 LABEL "http://www.palmpower.com" ID AboutAuthorLabel+2 AT (PREVLEFT PREVBOTTOM) FONT 0 LABEL "written by Alan Jay Weiner" ID AboutAuthorLabel+3 AT (PREVLEFT PREVBOTTOM) FONT 0 LABEL "email@example.com" ID AboutAuthorLabel+4 AT (PREVLEFT PREVBOTTOM) FONT 0 LABEL "http://www.ajw.com" ID AboutAuthorLabel+5 AT (PREVLEFT PREVBOTTOM) FONT 0 BUTTON "OK" ID AboutOKButton AT ( 62 125 37 12) USABLE FRAME FONT 0 END
Listing 1: "Hello World" resource script for PilRC
Alan Weiner is an independent software developer and a Senior Engineer at Communica, Inc. His email address is firstname.lastname@example.org.
Discuss this article on the PowerBoards.
-- Advertisement --
Palmtastik.com is your One-Stop Site catering to the needs of the discriminating 3Com PalmPilot and IBM WorkPad owner. Palmtastik is your definitive on-line source for the best PalmPilot software, including personalized City Guides, customizable Dining & Entertainment Guides, Games, Shareware, Utilities and Palm Accessories.
Palmtastik is the World's most comprehensive resource for PalmPilot fans, created by PalmPilot fanatics.
POWER TO THE PALM!
Copyright 1998, Component Enterprises, Inc. Contact: email@example.com. The Component logo is a trademark and PalmPower Magazine is a service mark of Component Enterprises, Inc. PalmPilot is a trademark of 3Com or its subsidiaries. The "PalmPower" term is used with permission of 3Com