The NEWMENU ProcedureMaking a procedure menu |
|
From "VS Procedure", Access 86, October 1986 |
|
[ Prior Article ] [ Return to the Catalog of articles ] [ Next Article ] |
Ask twelve programmers how they create thier application menus and you're likely to get twelve different answers. With options ranging from pricey menu applications with complete security features to simple EZFORMAT menus, it's no wonder there are so many approaches.
I have used several approaches to menu creation. I have written programs in most of the major languages, used EZFORMAT, and even created menu systems. In spite of this experience, my personal development menu is a procedure.
Why write menus in Procedure language? Procedure menus are easily written and maintained. They can provide most error checking, and may screen users from unauthorized options. They make it easy to set or reset user defaults. Best of all, they can be used to satisfy GETPARM screens without having to create a myriad of special-purpose procedures.
On the negative side, procedure-created menus are slower and offer fewer formatting options. Unless properly trapped for error and cancel conditions, they can be cancelled along with the programs they control.
This month's procedure illustrates a general-purpose menu that allows up to 15 programs. It accepts the screen information at the top of the procedure, then builds the screen accordingly. The basic process is similar to Richard Evans's March 1985 article in On-Line Data Access ("Programmer Development Menu") except for the use of four new Procedure features: 512-character string variables, the new CALL statement, the &LABEL step label verification function, and error and cancel exit trapping for the RUN statements. (Due to the use of these features, this procedure requires Procedure interpreter 3.00.10. This is the version shipped with operating system 6.40 or later.)
The procedure (see Figure 1) begins by creating a work table of text information to appear on the screen. This is accomplished by initializing a large string - 512 characters - with the items to be included. The text information is displayed within the PROMPT statement through a series of sub-string arguments to this large text string. The selected PF key is translated to the second half of a three-character string variable, &RUNSTEP; this will be used as our "soft" step label.
When the user presses a PF key, the integer value of that key becomes the last two positons of &RUNSTEP. How do we know if this newly-created step actually exists? A new Procedure built-in function - &LABEL - takes care of this. If the statement &LABEL(&RUNSTEP) is true (e.g. the value of &RUNSTEP exists as a step label) transfer passes to the CALL statement below. Otherwise, &ALARM is set and the user is asked for another selection.
If a valid selection is made, program control passes to the step label described by &RUNSTEP by invoking the CALL statement. CALL is similar to PERFORM in COBOL or GOSUB in BASIC; it transfers program control to the specified section, then returns to the point of origin after completing that section. Note that the end of a section must be indicated through an END statement.
In the example program, I have selected seven utilities to be run "straight" - e.g., without any procedural modifications to the default values. Notice step @6, however; it runs the REPORT utility but specifies several changes to the default values. Similarly, step @13 runs COPY, picking up the user-entered input file, library, and volume to act as the default values for the output file. These are small examples of the flexibility you gain in using Procedure to build menus.
Program control in most of the items is again assigned via CALL. This time, however, the file name is stored and a generalized RUN routine is called. Note the error trapping used in step SR; the CANCEL EXIT and ERROR EXIT allow the procedure to remain in control even if abnormal situations occur. To see how this works, key in a sample menu without these statements and run it. While in use, attempt to cancel the program (press HELP, then PF 16, and finally RETURN); the procedure will be cancelled in addition to the program.
When the selected program concludes, control is returned to the step label, then to the menu itself. The message field is updated to reflect the results of this processing. The user is now free to select the next item to be processed.
Adapting NEWMENU to your needs amounts to changing the data in step S00, then creating the appropriate steps (@11, @2, etc.) in the body of the procedure. Once a shell of the menu is created, this task shouldn't prove to be difficult.
I received a few responses to my challenge to readers in the July issue ("ACCESSCK - User Security Profile") for a way to print a copy of the screen from a procedure. As you might recall, I wished to use the SCREEN subroutine in the Usersubs library to print the screen, but was not able to do so because the address of the screen was not known. Thanks to David A. Mizzell of Houston for submitting the correct solution.
The answer lies in the use of the PROCMSG function, a relatively new Procedure language feature. As demonstrated in Richard Evans's "VS Update" of August 1986, the PROCMSG function turns off the usual screen input and output except when explicitly called from the procedure through a PROMPT or MESSAGE statement. When specified at the top of the procedure, this option closes the screen during processing but leaves the screen contents intact. With the workstation thus closed, the SCREEN subroutine can be used.
Here are the steps required to add screen printing cabability to ACCESSCK:
1. Add PROCMSG = NO at the top of the program (figure two). This will close the screen between PROMPT or MESSAGE statements.
2. Add the data elements required by the SCREEN Usersub (figure three). Notice that the screen status is specified as 'C' (closed).
3. Add logic to accept the PF key (PF 14 in this case) and branch to the SCREEN subroutine (figure four).
4. Add the call to the SCREEN subroutine itself (figure five). Notice that the print file name is displayed to the user in the message field, and that the value of &ALARM is set to "YES"; this will cause the terminal to beep when the message is displayed.
Don't forget I am still interested in any problems you might have that might be solved with a procedure.
That's all for this month, and keep those suggestions coming. Next month I'll discuss some of the other extensions within release 3.00.10 of the Procedure interpreter, and propose some of my own.
Figure 1: The NEWMENU Procedure
PROCEDURE NEWMENU ********************************************************************** * * NEWMWNU - Generic Menu Procedure * * This procedure was featured in the October 1986 ACCESS 86. It * allows users to build generic menus for any application. * * Modify to your own needs by changing the descriptions in &MDESC * and then adding appropriate step labels corresponding to the * displayed item on the screen. Any procedure statements may be * used within these steps. * * SPECIAL NOTE: requires 3.00.10 of the Procedure interpreter. * (This release came with OP/SYS 6.40; run PROC and check the * number at the top of the screen.) * * Written by Dennis S. Barnes * * MODIFICATION HISTORY * * Version 1.0 05/15/86 Initial version. * ********************************************************************** DECLARE &RUNFIL STRING (08) DECLARE &RUNLIB STRING (08) DECLARE &RUNVOL STRING (06) DECLARE &SYSVOL STRING (06) DECLARE &MESSAGE STRING (40) INITIAL "Welcome, friend" DECLARE &ALARM STRING (03) DECLARE &TITLE STRING (21) INITIAL "Personal menu for user " DECLARE &RC INTEGER DECLARE &MDESC STRING (512) DECLARE &RUNSTEP STRING (03) INITIAL "@ " EXTRACT &TITLE(19) = USERID, &SYSVOL = SYSVOL S00: ASSIGN &MDESC [ 01 ] = "CONTROL Control File maint. " [ 02 ] !! "DATENTRY Data Entry utility " [ 03 ] !! "INQUIRY Inquire/Extract data " [ 04 ] !! "REPORT Report utility " [ 05 ] !! "FILEDISP Find files on system " [ 06 ] !! "TIMERPT Run time report " [ 07 ] !! " " [ 08 ] !! "DISPMANY Display files in lib. " [ 09 ] !! " " [ 10 ] !! " " [ 11 ] !! " " [ 12 ] !! " " [ 13 ] !! "COPY Copy a file or library " [ 14 ] !! " " [ 15 ] !! "DISPLAY Display any file " [ 16 ] !! "EXIT Exit menu " S01: EXTRACT &RUNLIB = RUNLIB, &RUNVOL = RUNVOL ASSIGN &ALARM = "NO " S02: PROMPT PFKEY = &RUNSTEP(2,2), ALARM = &ALARM CENTER BRIGHT LINE &TITLE;; CENTER "(01) ", &MDESC((01*32)-31,32), " (09) ", &MDESC((09*32)-31,32); CENTER "(02) ", &MDESC((02*32)-31,32), " (10) ", &MDESC((10*32)-31,32); CENTER "(03) ", &MDESC((03*32)-31,32), " (11) ", &MDESC((11*32)-31,32); CENTER "(04) ", &MDESC((04*32)-31,32), " (12) ", &MDESC((12*32)-31,32);; CENTER "(05) ", &MDESC((05*32)-31,32), " (13) ", &MDESC((13*32)-31,32); CENTER "(06) ", &MDESC((06*32)-31,32), " (14) ", &MDESC((14*32)-31,32); CENTER "(07) ", &MDESC((07*32)-31,32), " (15) ", &MDESC((15*32)-31,32); CENTER "(08) ", &MDESC((08*32)-31,32), " (16) ", &MDESC((16*32)-31,32);;; CENTER BRIGHT &MESSAGE;; * No function assigned to key IF NOT &LABEL (&RUNSTEP) GOTO SCRNERR * Valid key pressed - perform option CALL &RUNSTEP IF &ALARM = "YES" GOTO S02 GOTO S01 * Invalid key pressed; display message SCRNERR: ASSIGN &ALARM = "YES" ASSIGN &MESSAGE = "Invalid PFkey pressed; please try again" GOTO S02 @1: ASSIGN &RUNFIL = "CONTROL " CALL @RUN END @2: ASSIGN &RUNFIL = "DATENTRY" CALL @RUN END @3: ASSIGN &RUNFIL = "INQUIRY " CALL @RUN END @4: ASSIGN &RUNFIL = "REPORT " CALL @RUN END @5: ASSIGN &RUNFIL = "FILEDISP" CALL @RUN END @6: RUN REPORT ENTER FUNCTION 04 ENTER OPTIONS ID = "TIMERPT ", OPTION = "YES", PAGE = "77" ENTER FUNCTION 16 END @8: ASSIGN &RUNFIL = "DISPMANY" CALL @RUN END @13: ASSIGN &RUNFIL = "COPY " R13: RUN COPY IN @SYSTEM@ ERROR EXIT IS E13 CANCEL EXIT IS @CANC F1: DISPLAY INPUT DISPLAY OPTIONS DISPLAY OUTPUT FILE = (F1.FILE), LIBRARY = (F1.LIBRARY), VOLUME = (F1.VOLUME) ENTER EOJ 16 E13: ASSIGN &RC = R13 IF &RC NE 0 GOTO @ERR GOTO ENDRUN @15: ASSIGN &RUNFIL = "DISPLAY " CALL @RUN END @16: RETURN * * ----- * Subroutines follow * ----- * @RUN: ASSIGN &ALARM = "NO " IF EXISTS FILE &RUNFIL IN &RUNLIB ON &RUNVOL GOTO SR IF EXISTS FILE &RUNFIL IN @SYSTEM@ ON &SYSVOL GOTO SR ASSIGN &MESSAGE = "Program " !! &RUNFIL !! " not found - please try again" ASSIGN &ALARM = "YES" END SR: RUN &RUNFIL IN &RUNLIB ON &RUNVOL CANCEL EXIT IS @CANC ERROR EXIT IS SRX SRX: ASSIGN &RC = SR IF &RC NE 0 GOTO @ERR ENDRUN: ASSIGN &ALARM = "NO " ASSIGN &MESSAGE = "Program " !! &RUNFIL !! " successfully completed" END @CANC: ASSIGN &MESSAGE = "Program " !! &RUNFIL !! " cancelled by operator" ASSIGN &ALARM = "YES" END @ERR: ASSIGN &MESSAGE = "Program " !! &RUNFIL !! " ended with error " !! &RC ASSIGN &ALARM = "YES" END
Copyright © 1986 Dennis S. Barnes
Reprints of this article are permitted without notification
if the source of the information is clearly identified