Techniques for Dealing with Non-Modal Programming

The following techniques will help you to write non-modal applications.

Make all panels self-contained. Since your call to fm_proc(), mn_proc() or cl_proc() returns before the user gets to enter data, any actions that you wish to take based on that data (storing it in a database, bringing up sub-forms, etc.) must be done in a user function that is attached, somehow, to this form. For the same reason, any action that you wish to take based on a menu selection must be done in a user function attached to your menu form. You can put this code into activate and suspend functions, begin- and end-form functions, menu action functions, or pushbutton action functions.

Disable the Exit and Quit keys for non-modal data forms and menus. These keys are usually assigned to the F10 and Esc keys. To disable them, remove the event functions from the appropriate event tables. If all your panels are non-modal, you can disable the keys throughout the application. If some of your panels are modal, you may wish to enable the Exit and Quit keys for the modal panels. This is part of the process of making all forms self-contained.

Put "Exit" and "Quit" pushbuttons on data forms, and "Quit" menu selections on menus. Again, this is part of making all forms self-contained. It does not matter what text you use for the pushbutton or menu item. You must force the user to exit or quit by using pushbuttons on a data form or by selecting a "Quit" item on a menu. You can then get control at the time the user is trying to leave the form, and can perform any necessary actions at that time.

Use static, global, or heap memory for all memory associated with non-modal panels. This includes data structures, any other data variables associated with fields, strings used to assign keywords for choice lists, help and memory files in your code, and any variables or data structures assigned to user pointers. If you do not wish to make these items static or global, allocate them from the heap using mem_get() or a similar function. This memory should not be allocated from the stack as local variables; this will cause a memory overwrite.

The actual form, menu and window pointers, and pointers to other structures that are allocated by Vermont Views (such as field pointers, choice list pointers, etc.) can be local variables. When you create a form by calling fm_def() or get a form from the library using dl_fmget(), Vermont Views allocates memory from the heap to store the form structure. The memory comes from the heap; the pointer to the memory is not important, since other functions can get a pointer to the memory by calling such functions as fm_namptr(), wn_namptr() and i_namptr().

Use the new window options AUTOUPDN and AUTOFREE appropriately. Because of the confusion and difficulty involved in trying to determine when you can safely take a panel off the screen and free it, Vermont Views has provided two new window options: AUTOUPDN and AUTOFREE.

If you turn the AUTOUPDN option on, Vermont Views automatically takes the panel down when the user exits or aborts it. If this option is on, you must not reference an object after the user has exited or aborted it, because the memory for that object is no longer available to you. If this option is on for a data form, for example, you may not call fm_rd() repeatedly on that form.

If you turn the AUTOFREE option on, Vermont Views frees the memory for the Vermont Views structure associated with that panel (the form and field structures, or the window structure) when it removes the panel from the screen. This includes all memory that Vermont Views allocated when you called fm_def() and fld_def(), wn_def(), etc., and all memory that Vermont Views allocated when you read a panel from a Designer library. Note that Vermont Views does not free memory that you allocate directly, such as memory to hold form data, or a memory file associated with a window. Freeing these objects is still up to you.

Use the proper type of user function for the task. Begin- and end-form functions will be called once during the course of processing this panel; activate and suspend functions will get called each time the user moves into or out of the panel. For example, the begin-form function is called the first time the user enters a form, and the end-form function is called when the user exits or aborts from that form. If the user suspends the form by temporarily moving to another panel, the begin- and end-form functions are not called a second time. However, if the user exits from a form (by, for example, pushing an Exit or Save pushbutton), then the next time he enters the form, the begin-form function is called again.

When the user suspends the form by moving to another panel on the screen, the suspend function is called for that form. When the user re-enters the form, the activate function is called. This is true no matter how many times the user enters and leaves the form. (Keep in mind that the activate function is also called when the user first enters a form, before the begin-form function, and the suspend function is also called after the user has exited or aborted the form, after the end-form function has been called.)

In general, the begin- and end-form functions should be used for actions that only need to be done once. Activate and suspend functions should be used for things that should be set and reset every time the user temporarily moves out of the form. For example, you should use a begin-form function to initialize your data variables for the form, since you do not want to re-initialize the data each time the user suspends and then re-activates the form. You should use an end-form function to save data in a database, since you only want to do this action when the user has completely filled out the form and is exiting from it (you might also do this in a pushbutton action function). If you have an event function associated with a special key, and this event function should only be called if the user is in a particular form, you should install the event function in an activate function and de-install it in the suspend function; otherwise, that key function will be available at inappropriate times. You want the key function to be available only when that form is the active form; therefore, you use activate and suspend functions to install and de-install it.

Another popular use of activate and suspend functions is to highlight the border of the active panel. The activate function draws the border in the highlight color; the suspend function redraws it in the inactive color.

Before your user function references another panel, determine whether that panel is in memory and whether it is on the screen. There is no way to predict whether the user has already put a particular panel on the screen, or even whether he has performed some action that caused the panel to be brought into memory. If your user function reads the form from a Designer library or calls fm_def() without checking whether the form already exists, you may have multiple copies of that form in memory.

All user functions that reference other panels are responsible for determining whether or not the panel is in memory, and, if so, whether or not the panel is already on the screen. If the panel is not in memory, the user function must create it in code or read it from the Designer library; if the panel is not on the screen, the user function must put it on the screen. Do not assume that, because a panel is in memory, it is automatically on the screen.

To determine whether a form or menu is in memory, call with the name of the form. To determine whether a window is in memory, call with the name of the window. If fm_namptr() or wn_namptr() returns a NULLP value, the form or window is not in memory.

To determine whether a form or menu is on the screen, call with a pointer to the form or menu. To determine whether a window is on the screen, call with a pointer to the window. fm_isup() and wn_isup() return a non-zero value if the form or window is on the screen.

Name all forms, menus and windows. If you are using the Designer, you must name panels in order to save them in the library. If you are writing your forms in code, assign names by using the function for forms and menus, and for windows. This will allow you to use the fm_namptr() and wn_namptr() functions mentioned above to determine whether the panel is already in memory.

More:

Additional Techniques for Non-Modal Menus


Home Contents Previous Next