Documentation  |   Table of Contents   |  < Previous   |  Next >   |  Index

6    Working with Tables and Lists

User Interface

Exploring Palm OS®

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 ^TOP^

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 ^TOP^

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 ^TOP^

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 ^TOP^

The table generates the event tblSelectEvent. This event contains:

  • The table's ID number
  • The row of the selected table
  • The column of the selected table

When tblSelectEvent is sent to a table, the table generates an event to handle any possible events within the item's UI element.

Lists ^TOP^

The list appears as a vertical list of choices in a box. The current selection of the list is inverted.

Figure 6.1  List


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 ^TOP^

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 

User Action

Event Generated

LstHandleEvent() Response

Pen enters a list box.

penDownEvent with the x and y coordinates stored in EventType.

Adds the lstEnterEvent to the event queue.

Begins tracking the pen without blocking. Responds to penMoveEvent and penUpEvent as appropriate.

Pen is lifted from the list box.

penUpEvent with the x and y coordinates stored in EventType.

Adds the lstSelectEvent with list's ID number and number of selected item to the event queue.

Pen is lifted outside the list box.

penUpEvent with the x and y coordinates stored in EventType.

Adds lstExitEvent to event queue.

Custom Drawing List Items ^TOP^

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 ^TOP^

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; 
      ... 
   } 
} 

Summary of Table and List Functions ^TOP^