Handling Events on Behalf of Forms
Large applications have complex event-handling requirements. You may need to manage moving focus in specific ways, handle specific key-presses, and often handle application events as well. In traditional BREW applications, this can lead to long and unwieldy event handlers, or a large set of functions to manage events by their type or application state, a situation which can easily lead to complex and confusing code.
By partitioning your application into forms, you can assign an event handler to each form, using the UI Toolkit's HandlerDesc structure and setting a specific event handler for a form. The HandlerDesc structure is a lot like an AEECallback structure. It simply records a function (your form's event handler) and the user data you'd like the event handler to accept. The UI Toolkit provides macros for filling and managing a HandlerDesc structure; as with similar kinds of structures in BREW, be sure not to allocate it on the stack, because it needs to persist throughout its use. Listing 1 sets up a HandlerDesc. This encapsulates the event handler for the MenuForm, the function MenuForm_HandleEvent (Listing 2), which must manage the events when you press the left or right soft keys.
(Listing 2) shows one of the best parts about working with forms: managing state changes. If you create your forms at application launch (or at least have their creation encapsulated in a construction method), switching screens is simply a matter of manipulating the stack of forms managed by your application's root form. At any time, the active viewthe one drawn to the screen and receiving eventsis the top form on the stack. The IRootForm interface allows you to push new views on the stack, pop views from the state stack, and even insert or remove items at any point in stack. Consequently, the MenuForm_HandleEvent method is trivialfor each of the soft key presses, it only pops the current form on the stack (which is the MenuForm) and then pushes the appropriate form on to the stack.
The MenuForm_HandleEvent must do one more critical thing: pass unhandled events on to the underlying form's event handler. This is crucial, because much of how the BREW UI Toolkit works is through event handling, and failing to chain to the underlying event handler will cause all sorts of nasty bugs and crashes. Fortunately, it's easy to do. When you initialize your HandlerDesc using HANDLERDESC_Init, it assigns the new event handler to the form, and returns the old event handler in your HandlerDesc structure. In your event handler, you simply pass unhandled events to the previous event handler using HANDLERDESC_Call. Using these macros, you can construct arbitrarily long chains of event handlers. When you're done with a HandlerDesc, be sure to invoke HANDLERDESC_Free, to ensure it's correctly freed. While not strictly necessary if you're only chaining two handlers together, for longer chains it’s crucial to avoid a memory leak.
Chaining has an important side effect that typically escapes people until after they've been bitten by it: you have to be careful about which methods you invoke in a chained event handler. Because so many parts of the form and widget frameworks communicate through event passing (even innocuous things like getting and setting properties can trigger event passing) it's very easy to get into situations where your event handler is calling itself recursively, trying to get the value of a property and calling itself over and over again. In general, it's best if you cache the data you need (at least the form or widget in question) in your application structure or the data structure you register in the HandlerDesc, and examine the incoming event before trying to perform operations on your application's forms or widgets. Fortunately, the frustration of this problem is easily offset by how easy it is to debug: on the simulator you'll hit a stack overflow instantly, so once you do, you know exactly what you're up against, and refactoring your code to avoid the offending call is often trivial. For a better understanding of the issue, peruse the various widget and form headers; they provide a list of the events used by the BREW UI Toolkit, which can help you avoid this problem in your design.