Forms support a concept of focus, where one item in the form is currently selected. Traversal refers to the user being able to shift focus from one item to another. In most cases, the MIDP implementation handles the details of Form traversal. In the Sun emulator, for example, you can move the focus through the items in a form by pressing the up and down keys. Focus is indicated by a solid black border around an item. Figure 7-2 shows a form with several items; the third item, an ImageItem, has the focus.
So far, so good—this is all pretty straightforward. As a matter of fact, the default implementation provided in CustomItem means you don't even have to think about traversal in many cases.
What makes things a little wonky is the concept of internal traversal. Some items support traversal of multiple choices inside the item. A good example is the ChoiceGroup item. The following sequence shows traversal through a form with three items in the MIDP reference implementation emulator. Figure 7-3 shows the traversal progressing from the text field through the gauge and into the ChoiceGroup.
Two methods signal traversal events. The first, traverse(), is called the first time the user traverses into the item. By default this method returns false, indicating that the item does not support internal traversal. The second method, traverseOut(), is called whenever the user leaves the item.
protected boolean traverse(int dir, int viewportWidth, int viewportHeight,
int[] visRect_inout);
protected void traverseOut();
| Note?/td> |
At first glance, you might expect custom items to receive calls on both the traversal methods and the key event methods when keys are pressed on the device. For example, if the user presses the down arrow key to move into the item, you might expect both the traverse() and keyPressed() methods to be called. In reality, the implementation should keep key events and traversal events unambiguous. Bear in mind that some devices will have alternate traversal controls (wheels, for example), so the implementation (and your custom item) should treat the events distinctly. |
If you do write a custom item that supports internal traversal, you need to pay attention to the arguments passed to traverse() and you need to return true to indicate that your item supports internal traversal. The information passed to the traverse() method is as follows:
dir indicates the traversal direction requested by the user. It is one of the following: Canvas.UP, Canvas.DOWN, Canvas.LEFT, Canvas.RIGHT, or CustomItem.NONE.
viewportWidth and viewportHeight indicate the size available for items in the Form containing this custom item. (In essence, viewportWidth and viewportHeight describe the content area of the Form.) These dimensions may be useful for determining the relationship between an item's choices and the amount of available screen area.
visRect_inout is kind of weird. It is an integer array with four elements. When the traverse() method is called, visRect_inout describes the region of the custom item's visible content area. When the traverse() method returns, visRect_inout should contain the bounds of the currently selected choice in the item.
If this is starting to sound a little hairy, just wait. The traversal mechanism is flexible enough to support different kinds of traversal. Some devices may only be able to support vertical traversal, while others may only support horizontal, and still others may support both. You can find out the device's traversal capabilities with the getInteractionModes() method, which can return CustomItem.TRAVERSE_ HORIZONTAL, CustomItem.TRAVERSE_VERTICAL, or both. Depending on the nature of the choices contained in your custom item, you may have to be flexible about the traversal directions you're receiving and the actual traversal inside the item.
Remember, the traverse() method is called when focus first comes to your item. If this method returns true, traverse() will be repeatedly called while traversal progresses through your item. When the user traverses out of your item, return false from the traverse() method. This lets the implementation know that internal traversal has ended. Most likely the implementation will call traverseOut(), although this only happens if focus actually moves away from the item. This may not be the case if the user has reached the end or beginning of the form.
All of this is discussed in meticulous detail in the API documentation for CustomItem's traverse() method. If you're planning to implement a custom item with internal traversal, go read the documentation a few times until it all sinks in.