Tables and lists are two types of user interface elements that present lists of data. This chapter describes how to use both types of user interface elements:
Tables
Lists
Tables
Tables support multi-column displays. Examples are:
- The List view of the To Do application
- The Day view in the Date Book
- The main view and the Edit view of the Address Book application
When you create a table resource, you set the table to display a certain number of rows and columns and you set the overall bounds of the table. The rest of the table initialization occurs at runtime in response to frmOpenEvent
.
It's important to remember that the number of rows and columns is fixed at compile time and cannot be changed at runtime. For example, the Address Book main view can display at most 14 table rows or contacts, but you may have several hundred contacts stored in the Address Book database. Many beginning Palm OS® programmers assume that the table contains rows for each of the hundreds of contacts but is only displaying 14. In reality, the table contains only those 14 rows that are being displayed. It's the application's responsibility to repopulate the table rows with data as the user scrolls the table up and down. Note that this is quite different from a text field, which conceptually holds the entire text of a document whether it can display the full text or not.
Each table is made up of the following:
- Columns - Each column contains a user interface element of a particular type. The available types of elements are listed in
TableItemStyleType
. - Rows - Each row shows a different set of data, for example, a database record or database row.
- Items - Items are the intersection of row and column, or a table cell.
For each item, the table stores three values: an integer value, a pointer value, and a font ID. Most of the table item styles, however, use only one of these three values. See the
TableItemStyleType
description to find out what values are applicable to what types of items.
When the user presses the stylus down on a table, it highlights the tapped item and that tapped item only. If you want the entire row to highlight, create a single-column table.
Initializing a Table
In response to the frmOpenEvent
, you should call TblSetItemStyle()
to set the item style for each row and column in the table, as shown in Listing 6.1.
Listing 6.1 Initializing a table
for (row = 0; row < rowsInTable; row++) { TblSetItemStyle (table, row, completedColumn, checkboxTableItem); TblSetItemStyle (table, row, priorityColumn, numericTableItem); TblSetItemStyle (table, row, descColumn, textTableItem); TblSetItemStyle (table, row, dueDateColumn, customTableItem); TblSetItemStyle (table, row, categoryColumn, customTableItem); }
Following this loop to initialize the style, you should call TblSetItemPtr()
or TblSetItemInt()
, depending on the style you set, to initialize the each item in each visible row.
You only need to set the item style once. You will need to set the item's value each time the user scrolls the table.
Table Callbacks
There are three possible callback functions that you might have to write to support tables:
-
TableLoadDataFuncType()
— Implement this callback if you have items that display editable text fields. It is called whenever the item with the editable text field is drawn or selected.The purpose of this function is to return a handle to the text that needs to be displayed.
-
TableDrawItemFuncType()
— Implement this callback if you've chosen a custom style. The custom styles mean that you want to control all aspects of table drawing.Most developers who use tables find that they need to use the custom table item and perform all drawing themselves.
-
TableSaveDataFuncType()
— This function is called only for the currently selected field right before the memory associated with the table is freed. You might implement it to free or to store the text associated with that field.
Table Events
The table generates the event tblSelectEvent
. This event contains:
When tblSelectEvent
is sent to a table, the table generates an event to handle any possible events within the item's UI element.
Lists
The list appears as a vertical list of choices in a box. The current selection of the list is inverted.

TIP: A list is not the same as a pop-up list, although the same set of functions is used to manipulate both. Pop-up lists are associated with pop-up triggers. See "Pop-Up Triggers" for more information about pop-up triggers.
A list is meant for static data. Users can choose from a predetermined number of items. Examples include:
- The time list in the time edit window of the datebook
- The Category pop-up list (see "Category Controls" in this chapter)
If there are more choices than can be displayed, the system draws small arrows (scroll indicators) in the right margin next to the first and last visible choice. When the user taps a scroll indicator, the list is scrolled. When the user scrolls down, the last visible item becomes the first visible item if there are enough items to fill the list. If not, the list is scrolled so that the last item of the list appears at the bottom of the list. The reverse is true for scrolling up. Scrolling doesn't change the current selection.
Bringing the pen down on a list item unhighlights the current selection and highlights the item under the pen. Dragging the pen through the list highlights the item under the pen. Dragging the pen above or below the list causes the list to scroll if it contains more choices than are visible.
When the pen is released over an item, that item becomes the current selection. When the pen is dragged outside the list, the item that was highlighted before the penDownEvent
is highlighted again if it's visible. If it's not, no item is highlighted.
An application can use a list in two ways:
- Initialize a structure with all data for all entries in the list (either in the resource file or in code at form initialization time) and let the list manage its own data.
- Provide list drawing functions but don't keep any data in memory. The list picks up the data as it's drawing.
Not keeping data in memory avoids unacceptable memory overhead if the list is large and the contents of the list depends on choices made by the user. An example would be a time conversion application that provides a list of clock times for a number of cities based on a city the user selects. Note that only lists can pick up the display information on the fly like this; tables cannot.
See "Custom Drawing List Items" for sample code of how to draw list items.
List Events
Although lists generate events, you typically do not have to respond to events for a list. Instead, you check the value of the current list selection using LstGetSelection()
or LstGetSelectionText()
when some other event occurs.
NOTE: You cannot call
LstGetSelectionText()
if you call LstSetListChoices()
and pass NULL
or something other than the actual list items as the itemsText
parameter. See "Custom Drawing List Items" for details.
The LstHandleEvent()
function handles list events. Table 6.1 provides an overview of how LstHandleEvent()
deals with the different events. For the event flow for pop-up lists, see Table 3.8.
Table 6.1 Event flow for lists
|
Adds the Begins tracking the pen without blocking. Responds to |
|
|
Adds the |
|
|
Adds |
Custom Drawing List Items
When the items in a list must be generated at runtime and can be quickly generated in any order, use a callback function to draw the contents of the list instead of providing the list with static strings.
In the frmOpenEvent
, set the draw function and the number of items in the list. See Listing 6.2.
Listing 6.2 Setting up a custom drawn list
case frmOpenEvent: lstP = (ListType *)FrmGetObjectPtr(frmP, FrmGetObjectIndex(frmP, MainTimesList); LstSetDrawFunction(lstP, ListDrawCallback); LstSetListChoices(lstP, NULL, 24); break;
Notice that this example passes NULL
for the itemsText
parameter of LstSetListChoices()
. For static lists, the list contains a pointer to an array of strings that it displays for each item. When your application calls LstSetListChoices()
, this parameter sets the value of the list's pointer. Because the application is going to draw the list items, it sets the pointer to NULL
. This means that the application cannot call LstGetSelectionText()
to retrieve the list selection because the list does not know what the text is.
The callback is called for each line in the list that needs to be drawn. Fonts and colors have already been set.
Listing 6.3 Custom list drawing callback
void ListDrawCallback(int16_t itemNum, RectangleType *bounds, char **itemsText) { char buffer[bufferStringLength]; // set the buffer based on the itemNum. GetListItemText(itemNum, buffer, bufferStringLength); WinDrawChars(buffer, strlen(buffer), bounds->topLeft.x, bounds->topLeft.y); }
One of the benefits of having a draw function is that you do not need to worry about keeping track of memory that would have to be allocated for the list's contents. However, the drawing callback function will be called often. In addition to being called to draw each item, it is also called (with different foreground and background colors) to highlight or un-highlight items as the user taps them, so it needs to be fast. If it isn't fast enough, consider creating the list of strings beforehand. Another option is to have your callback function generate each item as necessary but store them in itemsText
for fast access in case they are needed again.
Because calling LstGetSelectionText()
is often not possible when you provide a custom drawing function, it's convenient to have a single function that copies the text for a given item number into a buffer. You can then call that function in both the drawing callback and in response to lstSelectEvent
. For example, Listing 6.4 uses the same GetListItemText()
function as is used in Listing 6.3.
Listing 6.4 Responding to lstSelectEvent for custom drawn list
case lstSelectEvent: GetListItemText(eventP->data.lstSelect.selection, lstSelection, lstSelectionSize); break;
Using Lists in Place of Tables
Lists really consist of single-column rows of text, but it is possible to imitate a multi-column display if you provide a custom list drawing function. Many programmers choose to use lists instead of tables for multi-column displays because lists are generally easier to program than tables are. Doing so is acceptable, but it is somewhat problematic because the list always displays a rectangular border around the list. If you choose to use lists to display multi-column data that would normally be displayed in a table, you must suppress the drawing of the list border. The safest way to do so is to set the draw window's clipping rectangle to the bounds of the list before drawing the list, as shown in Listing 6.5. See Exploring Palm OS: User Interface Guidelines for more information.
Listing 6.5 Suppressing the list border
void DrawFormWithNoListBorder(FormType *frmP, uint16_t listIndex) { RectangleType *clip; RectangleType *newClip; ListType *listP = FrmGetObjectPtr(frmP, listIndex); // Hide the list and then draw the rest of the // form. FrmHideObject(frmP, listIndex); FrmDrawForm (frmP); // Set the clipping rectangle to the list boundaries and // draw the list. This suppreses the list border. WinGetClip(&clip); FrmGetObjectBounds(frmP, listIndex, &newClip); WinSetClip(&newClip); LstSetSelection(listP, noListSelection); FrmShowObject(frmP, listIndex); // Reset the clipping rectangle. WinSetClip(&clip); } Boolean MyFormHandleEvent(EventPtr eventP) { Boolean handled = false; FormType *frmP; UInt16 listIndex; switch (eventP->eType) { case frmUpdateEvent: frmP = FrmGetActiveForm(); listIndex = FrmGetObjectIndex(frmP, MyListRscID); DrawFormWithNoListBorder(frmP, listIndex); handled = true; break; ... } }