Author: Robert Mykland, Palm OS Programming from the Ground Up the author, published by Osborne McGraw-Hill issued a number of quick and easy to use design methods, most of the code enables Palm OS applications can be applied to the next Palm OS application. The content I want to introduce this article is the separation of public headers, event abstractions, methods, and interfaces in C language, data package, polymorphism, and reusable UI custom and type abstraction. Many people (including me) are attracted by C and Java because the code they generate supports reuse and group cooperation. However, these large languages restrict resource scalability of Palm handheld devices, and it is difficult to make 68K Palm applications to achieve expected performance. As the emergence of rapid ARM-based handheld, this problem is no longer as serious. However, users will not be worried about performance, they will complain that the applications generated by these languages are too large. For these reasons, since the version 1.0, C has also continued to be the preferred programming language of most professional PALM developers. C provides the smallest code size and is best in all advanced languages. Moreover, when using C, if you can follow some design principles, you can benefit from this more object-oriented language. Finally reach an object-oriented ideal state. If you use incorrectly, you cannot get these benefits from C and Java. Data package data packaging is an object-oriented idea. It puts the data into the object, and the code other than this object cannot access these data directly. You can usually modify data within a range, which avoids BUG due to modifying data outside of this range (except for terrible pointers). Data packages are also conducive to code reuse. Since the data is not messy allocation, it is easy to access, modify, compile, so it can be easily reused to other places. If there is no data package, some key error code will spread into the range of the entire application. In this way, it takes time to remember (or remind), then correct it. I think the best data package in the C language is in the code organization to * .c module, and there is no global variable, so data can only be modified in the specified * .c module. A clearly defined Palm code role is usually only a few, so this approach is also very easy to manage even for large PALM projects. In my Palm application, the code for each database is organized into different modules. The code for each form is placed in different modules. Each menu item usually has its own module. Custom controls and dedicated standard Palm controls have their own modules. In the new application, it can be mixed with these modules. Data Abstract All variables declare into function internal variables or static variables, you may want to know, (for example) if a form needs to set a record attribute for a database, what should I do? The answer is to declare the variable into static in the database module (if you need to be permanently exist, you can declare a global variable of the database), and write a access function to modify the data. The access function is only used to modify the data, or a copy of the data is returned. Is these extra work worth it? Absolutely worth it, because: 1) This module can be clean from an application to another application, 2) Control how other modules access these data, this is perhaps the most important, 3) When BUG occurs You can know where to set a breakpoint. For example, a module has some code used to use the control to create a custom table.
This form is based on an entry in the database or is based on a static data generated by some modules (eg, database modules). When the first module is to access data in the second module, a custom function for data package should be invoked, such as getTableEntryControlType (), instead of reading the data structure directly from the second. Functions getTableEntryControlType () may be as simple as the following: uint16 getTableEntryControlType (u16acontroltypes [u16row]);} There is also an important feature of programs we have written, as long as this function returns a double byte according to the specified format. Data, we can change the expression format of internal data. For example, we can store it into the database instead of placing in a static table. The number of calls outside is not necessarily changed. This is the power of data abstraction. If a dedicated control is written, all of its configuration data is obtained through a function call, then don't care about those data from constants, static variables or databases. Whether it is a control, a form or other object, it can be used immediately, and it can be reused in any case. There are other ways to use data abstraction to reuse the code, that is, constant. Define a universal header file throughout the application for defining constants. I always named it app.h. With this approach, it can be mixed with my form, the main routine, and database resources. They all only reference this header file, and the required data is also obtained from this header file, for example, define data of its behavior in different application contexts. This is not only convenient, but also a big advantage, when a bug is corrected, even if the top header file is modified, the reusable module is not required. Behind I will then discuss App.h, there are some similar data abstraction usage. I like to define the minimum and maximum PALM OS version number that the program can run. I like to start the form as an abstract name as StartForm, and define it for a particular application in App.h. I also like to define a creator ID to define a string and four-character numbers: // define the creator ID
#define app_creator_id_char 'srvr' #define app_creator_id_string "SRVR" These definitions can be reused anywhere. The database code also references these creator IDs and benefits from this abstract usage. Inheritance inheritance is a kind of thinking: handling basic features in an object, then create a dedicated object to inherit the characteristics of the basic object. For example, in C , you can create a control, inheriting some graphic text from another object; then inheriting string expression and operation functions from the third object; third objects inheriting the original data move from other objects operating. In the Palm application, there are several places to use C inheritance very useful. One is a database. The other is a custom control. Palm OS provides some API functions for operating the recorded database. I have written several different modules that can organize these APIs. One of the modules is small and fast, only to split and adjust records. Another module is relatively rich, and even the ordering operation, the operation and relationship operation of the query. When I need to use a dedicated database in the Palm application, I often reuse one or all of these two modules as the basis for the dedicated database. Because the contents of these two universal databases are in their respective independent modules, each particular database is placed in their respective independent modules. In order to inherit the needs, these objects can be used like object bindings. This modular level inherits, well-applied to custom and custom controls. I have written some basic controls similar to the standard PALM OS control. These controls can be mixed and combined into a new more complex control. The new control inherits the characteristics of the basic control constituting it. Reusable UI custom I will talk about how to use all the custom and custom controls I created. The functions of the support check box control are listed below:
void CbxCloseAll (void); void CbxDraw (FormGadgetType * spCbx); Boolean CbxEnabled (FormGadgetType * spCbx); void CbxErase (FormGadgetType * spCbx); Boolean CbxGetValue (FormGadgetType * spCbx); Boolean CbxHandleEvent (EventPtr spEvent); void CbxHide (FormGadgetType * spCbx); void CbxHit (FormGadgetType * spCbx); Uint16 CbxOpen (FormGadgetType * spCbx, Boolean oEnabled, Boolean oValue); void CbxSetEnabled (FormGadgetType * spCbx, Boolean oEnabled); void CbxSetValue (FormGadgetType * spCbx, Boolean oValue); void CbxShow ( FormgadgetType * spcbx); Boolean CBXValidatePointer (FormGadgetTyPe * SPCBX); For many functions in this, there are similar functions in the Palm OS. These functions can be used seamlessly to the control, and can even replace the PALM OS function directly with my function, and check if the control is customizable. If the standard control is called, the appropriate PALM OS system function is called. This way, my custom control can be used with the Palm OS standard control. The above functions are just one of this seamless integration. Functions CBXCloseall () Releases the memory occupied by all custom check box on the current form. This function may be used in the FRMCLOSEEVENT event handler. When running normally, the function CBXDRAW () draws a check box. The function cbxenabled () is used to query the status of the check box. Function cbxrase () Delete check box. For check boxes, CBXgetValue () is the same as the cbxenabled () function. When merging a set of controls while supporting these two functions means that you don't have to be more than what function calls, and what an event is handled in any way. This function is recommended. Functions cbxhandleevent () processes all special events on all check boxes on the form, making them more like a normal Palm OS standard control. For example, you need to draw check boxes when using Formnenevent and FormUpdateEvent. The PENDOWN and PENUP events are used to analyze whether they happen within a custom check box. If the condition is met, the user-defined event CBXEnterevent and CBXExitevent will be added to the queue and the user-defined event CBXSelectEvent will also be added to the queue. These controls can then be processed in your code like processing a regular checkbox. Function cbxhide () Delete the check box and set its "usable" attribute (defined in dynamic allocation) to false. The function cbxhit () adds the CBXSerectEvent event to the queue. Function CBXOpen () Initialization check box, ready for use of this check box. You may also guess, function cbxsetenabled () is used to enable / disable check boxes. Functions CBXSetValue () Accept a Boolean value, and use it to set the check box. Functions CBXSHOW () makes the check box available and draws them. Functions CBXValidatePointer () is used to identify whether the custom control is a real check box.
With such a function, you can create custom controls that can be seamlessly mixed with the Palm OS standard control. Polymorphism is a big topic relative to simple things. Basically, everything we do is in handling the object (for our C, the code body), which is generally used to encapsulate various operations. From this point, you need to organize C in C . But this also highlights the effect of code reuse. I use polymorphism when loading the form. My main executive routine is fully universal and has been reused many times. When a new form is loaded, it needs to load the event handler of the form. Function call to complete this work is actually defined by #define, I put it in the universal header file app.h. Therefore, the code for loading the event handler is as follows: // load a formif (sevent.type == frmloadEvent) {uint16 u16formid; // the form ID forwardptr spform; // points to the form // Get the ID u16formID = Sevent.data.frmload.formID; // initialize the form spform = frminitform (u16form); // establish the Event Handler
FRMSETEVENTHANDLER (SPFORM, GETEVENTHANDLER (U16MMID)); // Point Events To Our FormsetActiveform (SPFORM); // Draw The Form
FRMDRAWFORM (SPFORM);} The function getEventHandler () is located in a define statement in App.h, as shown below:
// this creates the function geteventhandler () // That Returns The Event Handler for a given form // in this application.
#define EVENT_HANDLER_LIST / static FormEventHandlerPtr getEventHandler (/ Uint16 u16FormID) / {/ switch (u16FormID) / {/ case AboutForm: / return (aboutFormEventHandler); / case DestinationForm: / return (destinationFormEventHandler); / case FeaturesForm: / return (featuresFormEventHandler) ; / case HomesForm: / return (homesFormEventHandler); / case NotesForm: / return (notesFormEventHandler); / case RemarksForm: / return (remarksFormEventHandler); / case ThisHomeForm: / return (thisHomeFormEventHandler); /} / return (NULL); / } Then instantiate the function in main.c. There is such a line of code: // the event handler list event_handler_list This, the main function does not have to know what form can be loaded or will be loaded because they are all defined in the universal header file. This function is in this function. In addition, I have handled the MAIN function and event processing code to be reused in the way of dealing with fatal errors and programs exit / cleaning. In this case and in the following cases, the polymorphism has become an abstraction. Because, although there is no important event like AppStopevent, it is possible to handle it if you are fully prepared. The main problem is, just like other event-driven applications, Palm OS applications also need to have an environment that controls the event loop. Sometimes it is necessary to intercept specific events in the same way to avoid analysis and processing them. Sometimes you need to temporarily add events, such as update animations, making it run in normal speed. To do this, the best way is to use the tools provided by Palm OS, ie ERRTHROW and ERRCATCH. In my main.c, the event loop is like this: // begin the try blockerrtry {// Initialize all parts of the application appinit (); // Wait Indefinitely for Events
While (True) Processevent (-1);} // service any fatal alerts
Errcatch (u32alert) {if (u32alert) frMalert;} ErrendCatch Event Process Process Processevent () requires a parameter. This parameter represents the time of waiting for the event, and the unit is 1/100 seconds. Similarly, you can also create a small event loop in other places to implement the following features:
While (OEXITANIMATION == false) {processevent (10); AnimationStep ();} In the above example, the program will update an animation every 1/10 seconds. This has a big benefit: If you retrieve the AppStopeVent event in the event loop, you can return to the Catch statement in Main.c through a virtthrow (0) call regardless of the Custom Event cycle. If this cannot be achieved in a polymorphic manner, it can only be handled at each place that may receive Appstopevent. That will bring a lot of work and bugs. Maybe you will need to do some cleanup work. For example, the deep nesting custom event loop is required to receive AppStopeVent, you need to do some cleaning work. In this way, we need to use polymorphism in another way to bind different separate modules and generate main.c universal code. In the header file app.h, two functions are defined, named Appinit () and appStop (). These two functions are actually macro, they call a series of initialization functions and termination functions. These initialization functions and termination functions belong to each module in the application. Call them in the MAIN routine. Note that the appinit () call is included in an Errtry block. This way, I can avoid fatal errors in the initialization function of these modules. For the animation cycle above, you need to release some memory when you receive AppStopevent and exit it. In this case, it is best to place the code in the termination function of the module, and check if it also occupies the memory in the termination function, if it is, it releases it off. The last primary usage of polymorphism can also be used to reuse the code, I just use it to handle the menu and vegetable strip. In an application, you may reuse forms in another application. The menu of the two should be completely different. This means that even if it is just a menu, it is also necessary to modify the form code. There is a way to solve this problem. For each form in the application, a macro is defined in app.h to process the menu event of the form. In App.h, the process function of the menu event can be defined, so that the form and its menu item are separated, which increases the reuse of the form and menu code. Macro is as follows: // The menu Event Handler Macro for The "Remarks" Form