Paradox Community
Search:

 Welcome |  What is Paradox |  Paradox Folk |  Paradox Solutions |
 Interactive Paradox |  Paradox Programming |  Internet/Intranet Development |
 Support Options |  Classified Ads |  Wish List |  Submissions 


Paradox Programming Articles  |  Beyond Help Articles  |  Tips & Tricks Articles  


Implementing a Table Based Menu System
© 2001 Carolyn Wendover

Introduction

In most applications you will want to provide navigation though a custom menu system. Paradox provides menu and pop-up menu objects to facilitate building menus, and the menuAction method for handling menu selections. However, if you build and handle your menus on each form this can get quite cumbersome as your application grows.

An approach I have used for years is a table based menu builder. In 1994 Leon Chalnick presented a pair of articles in the Paradox Informant detailing this approach (PI, Mar. and Apr. 1994) and provided the code and table needed to implement this solution. I do not intend to go into that amount of detail here but will present a description of the table needed, how to populate the table, and what library calls need to be added to your code. For a fuller explanation of how the library actually builds and handles menus please refer to Mr. Chalnick's original articles.


Using the table based approach you can easily define the table such that:
  • Menus can be automatically tailored based on each user,
  • New menu items are added throughout the application by simply entering a new record in the table.

The Menu Table

Each record in the menu table represents one menu item. Fields in the record are used to specify the text of the item, it's initial state, the security level of the item (explained below), and the type of action that happens if the item is selected. The resultant action is either to open a form, perform a standard Paradox menu constant action, execute one of your library methods, or open/print a report.

I am including the menu library that you need to implement this approach as well as a sample table and two forms that demonstrate what to do.

Let's get started with setting up the table. The table structure of the menu table is described below:

Field Type/Size/Key Picture
MenuTag S//key field  
Parent A/40  
Item A/40  
ParentOrder N  
ItemOrder N  
P4Wconstant A/30  
InitialState A/4 *{H,D,G} 
AcceleratorKeys A/20  
RightJustify A/1 {Y,N} 
Exec A/10 {Form,Method,Report,Action} 
MultiInstance? A/1 {Y,N} 
Security A/1 You define 
Exclude A/20  
Lib A/30  
Param A/80  

There is one secondary index defined for the table. It consists of the Parent order and Item order fields and is called Parent-Item-Order.

MenuTag - Serves as the primary key for the table. You can reference a menu selection by its text value or an integer "tag". Paradox allows you to specify your own menu tags between the values of 1 and UserMenuMax (varies depending on the version of Paradox, but it is generally around 2000). You can use any number between 1 and UserMenuMax. While this is the primary key for the table, it does not affect the order that your menu items appear. That is controlled by the Parent order and Item order fields.

Parent - This is the text of this item's Parent item. For instance, if you plan to have a main menu item named "File" with items of Open, Close, and Exit under that. Then for the records for Open, Close, and Exit the Parent field would be File.

This is a good point to note that this menu building routine also supports underlined hotkeys for menu items. To have the system automatically set this up, you simply precede the letter you want as the hot key with an ampersand (&). So, if you want the F in File to be your hotkey, you would list the Parent field as &File in this case. For items that you want to appear on the main menu bar across the top, you use a Parent of Main (no &).

Item - This is the text that you want for the menu item. Use an & to indicate the desired hot key. So if we were entering the record for the Open command it's Parent field would be &File and it's Item field would be &Open. There are also four special entries recognized for this field: separator, bar, break, and &Window. Separator inserts a horizontal line in your drop down menu. Remaining items for this same parent continue below the line. Using Bar adds a vertical line to your menu. Remaining items for this parent start in a new column to the right of the bar. Break is similar to the Bar item except no line is inserted. Instead, remaining items start in a new column to the right of the first column of menu items. By using break after each item in the table, you can cause your drop down menus to appear as a horizontal menu bar below the main menu bar. These are demonstrated on the associated form.

The use of &Window is a little different. This adds a menu item to the main bar. Under it are listed all open items within Paradox (including forms, reports, Project Viewer, tables, etc.) with a checkmark in front of the current screen. Selecting one of the listed items brings it to the top. This is the standard Windows function found in most other Windows applications. It takes two records in the menu table to implement this. You will have one record where the Parent item is Main and the Item field is &Window. The other record you need is one that has &Window as the Parent item. The Item field for this record can be separator, bar, break, or any text you want (like "below is a list of available windows:"). Included in the menu library is the method I use. I enter an Item field of "Close Extra" (without the quotes). It calls a library method (how to do this is described below) called CloseMost. That method closes all open form and report windows except for one called Title Page. The purpose is to provide users a way to close all other application windows and just return to the title page. If you want to use this approach you need to ensure you modify the CloseMost routine to indicate the title of the page you want left open.

ParentOrder / ItemOrder - This pair of fields describes to the library the order the items are to appear across the top of the page and the order of the items in the drop down menus below those items. The most important thing to remember when defining these items is that you need to have a child menu fully defined before the parent menu (with respect to the Parent-Item-Order index). So all items that you want listed across the top in your main menu selections will be at the end of the table. If some item in one of your drop down menus has another menu below it, then that lower menu has to be in the table before it's parent. When entering records into the menu table, it is best to switch to the secondary index of Parent-Item-Order. This way, you can visually check that your sub-menu items are appearing ahead of their parent items. Another useful tip when filling in the menu table is to give your ParentOrder and ItemOrder fields values in increments of 10. That way, if you later want to insert another menu item between two existing items, you can do that without having to resort to smaller and smaller decimal differences between numbers.

P4Wconstant - One of the features ObjectPAL offers, is the ability to invoke most of the standard Paradox menu options from within code using MenuCommands. You can use this field to specify any of these commands and it will behave as if it was called from the regular Paradox menu. For example, if you wanted to offer the command to Tile all open windows in your application you could add a menu table item to appear under the main &Window option. The Parent field for this record would be &Window, the Item field could be &Tile Windows, and you would enter MenuWindowTile in the P4Wconstant field. I often use the MenuFilePrinterSetup menu command at the end of my list of available reports as a way for the user to easily access the Printer Setup screen.

InitialState - This allows you to specify the initial state of the menu item when it is created. The choices are (D)isabled, (G)rayed, and (H)ighlighted. More than 1 can be specified for an item.

AcceleratorKeys - This field provides a way for you to document for the user what alternate hot key controls you have programmed into the application for this item. For example if you wanted the user to be able to print report 1 by pressing the Alt-1 key combination you could enter "Alt-1" (without quotes) in the AcceleratorKeys field for that item's record in the menu table. HOWEVER, the menu handling routine is not set to automatically recognize and handle this key combination so you would still need to program for the actual handling of this (probably in the form keyPhysical method). I am working on a menu library method that will handle these, but in the interest of getting this article done this year I leave that to the reader to work on also. <g>

RightJustify - This Y/N field can be used to indicate if you want the menu item to be right justified in the menu. The default is to left justify it.

Exec - You can enter one of four values in this field: Form, Method, Report, or Action. The value of this field causes the library code to either open a form, execute another library method, open/print a report, or execute an Action Command (like DataBeginEdit). Which form, method, report, or action is used is indicated in the Parameter field described below.

MultiInstance? - Use this Y/N field to indicate if you want to be able to open multiple instances of a form or report. If you indicate Yes then each time the menu selection is made, the system opens the indicated object. If you enter No then the library first tries to find an open copy of the form or report. If there is one it attaches to it and brings it to the front. If there is not an open copy, it opens it.

Security - One of the features of this menu approach is that you can set up the table so that different users have access to different menu selections. This is implemented using this security field. The easiest way to explain how to use this field is through an example. Lets say you have three categories of users: Data Entry, Administrative, and Financial. You could enter a D in the Security field for all menu items that you want to give Data Entry people access to, enter an A for all Administrative type items, and F for all financial or billing related items. Then in your login process you identify the user and determine their access level (perhaps looking it up in a password table). You pass their access level to the menu building routine and only those items that match their access level are included in their menu. So, for example, if the access level for one user was DF, then they would end up with a menu that has Data Entry and Financial item, but no Administrative level items. At an extreme level, you could give each item it's own Security ID character, and define very long security strings for each user that indicates each menu item they have access to.

Exclude - This field can be used to override the Security values. For example, lets say you have given access to a user for various data entry screens as well as report screens using the Security field and their access level. In your menu you have entries for things such as Begin Edit, End Edit, Next Record, Previous Record, etc. These entries really only have meaning for data entry screens and not for report generation screens. You can assign a code for all menu options that only pertain to data entry actions and enter it in the Exclude field for each of these menu records. Then when you call the routine to build the menu for a report screen you pass it the exclude code and the data entry actions are included on the menu but are grayed out and disabled.

Lib - If you have specified that this option is to execute a library method, this field gives the name of the library containing that method. If there is an alias associated with the library you can include that also.

Param - This field contains different information depending on the action that will be executed. If you are executing a method, this field contains the method name. If you want to open a form you specify the form name and title separated by a vertical bar (:formAlias:formName|formTitle). The reason a title is specified is because the menu building routine will use that to assign a title to the form. This will also be used to determine if the form is already open if you do not want to open multiple instances. If you want to open a report, it will contain the report name, title and orientation ("Portrait" or "Landscape") separated by a vertical bar as is done for forms (:reportAlias:reportName|reportTitle|reportOrientation). In the case of an action command, enter the action constant name (such as FieldForward or DataBeginEdit).


Alternative Menu Table for On-Screen Reports

As an addition to this original menu table I have found it useful to create and use a similar table to define menu options for reports viewed on the screen. Since reports cannot process any code, menu items are limited to those items that can be expressed as Paradox menuCommand constants and many of the fields used to build regular menus are not needed for reports. Fields in this table include: Menu tag, Parent, Item, Parent order, Item order, P4W constant, and Accelerator keys.

The use and functionality for Menu tag, Parent, Item, Parent order and Item order are the same as described above. Each record in this table will have a P4W constant that is a menuCommand unless it is adding a formatting item (separator, bar, or break) or is an item with "Main" as the parent. The only accelerator keys you will use are those that Paradox already handles on it's own for a particular command (for example Shift+F4 to move to the next page in a report).

If you indicate that a particular menu selection is to open a report, and the user chooses to view that report, the HandleMenu method will automatically call the procedure needed to build the report menu, based on the report menu table. If you name the report menu table something other than rptMenu, modify the menu library routine mGetReportMenu to indicate the name and location of the table. You can also call this method directly if you open a report using your own ObjectPAL code. There is an example of this in the associated demo.


Part 2 of Implementing a Table Based Menu System


Discussion of this article


 Feedback |  Paradox Day |  Who Uses Paradox |  I Use Paradox |  Downloads 


 The information provided on this Web site is not in any way sponsored or endorsed by Corel Corporation.
 Paradox is a registered trademark of Corel Corporation.


 Modified: 15 May 2003
 Terms of Use / Legal Disclaimer


 Copyright © 2001- 2003 Paradox Community. All rights reserved. 
 Company and product names are trademarks or registered trademarks of their respective companies. 
 Authors hold the copyrights to their own works. Please contact the author of any article for details.