Creating a Dialog Box with Linked List Boxes This technote demonstrates how to mimic the Superbase Field Selection dialog box (with some minor differences). The Superbase Dialog Editor allows list boxes to be used, but not to select items from one list and display them in another. This technote explains how to accomplish linked list boxed through program control. There are some differences between this dialog box and the field selection dialog box in Superbase. In Superbase's field selection dialog box: When there are no fields selected, the OK, CLEAR and DELETE buttons are dimmed. This effect can be added by placing an ADD DIALOG statement where the parameter for style is 0. This specifies a non-highlighted command button. You can make a field selection by double-clicking. When a field is selected it is not removed from the original list. In the program that follows, this is an extra feature which can be turned off by not modifying the List$ array in SUB switch(). When you select OK, the database file view is modified. The dialog in this example simply prints to the screen which fields where selected. To achieve a field selection you could remove the Prnt() routine and add an OPEN FIELDS statement. Note: using variables in an OPEN FIELDS statement requires the use of EXECUTE. When the following program is executed, it displays two list boxes on a dialog. The left list box displays the fields from the current file. The list box on the right displays the fields which the user has selected. Since the dialog variables are not updated until the dialog box is exited, a program must be used to examine the users selections, modify the list box arrays and then redisplay the dialog box. Because the dialog box is redisplayed there will be some screen flicker. Building a dialog box To build a dialog box, use the Dialog Editor, available under the Program menu. The dialog box for this example is constructed of two list boxes. Each list box uses two arrays: one to display information and one to return the user's selection. The array names are as the appear below. When defining the list boxes select options for "Allow multiple selections" and "Vertical scroll bars". Listbox$(): List contents array Dispbox$(): List contents array Selection$(): User selection array Selection2$(): User selection array The program is designed to handle eight buttons. You may use more of less if desired. The buttons and their parameters are as follows. CANCEL No Update on exit / Return value = 0 OK Update on exit / Return value = 1 CLEAR Update on exit / Return value = 2 INSERT Update on exit / Return value = 3 INSERT ALL Update on exit / Return value = 4 DELETE Update on exit / Return value = 5 For more information regarding designing and building dialog boxes refer to the Developing Applications manual. REM******************************************************************************* REM Main REM This routine sets up the program, controls the overall flow of the program and cleans up before REM exiting the program. The program first turns on error trapping. The primary concern of error REM trapping in this program is to make sure there is a file open. Then the initialization procedure is REM called. Procedure Init dimension all of the arrays used by the dialog box and fills the array used REM to display the fields list. The dialog is then built in memory with a call to diafs. The While loop REM continues to redisplay the dialog box until the user selects OK or Cancel. Procedure diacase REM executes a CASE statement depending on the user selection returned from the dialog box. If the REM user selects OK, when the While loop is exited the user's selections will be displayed to the REM screen. REM******************************************************************************** SUB main() ON ERROR GOTO errcheck CLS CALL init() :REM Initialize list array CALL diafs() :REM Build dialog box in memory flag% = 0 WHILE flag% = 0 DIALOG "FieldSelect",button% :REM Redisplay dialog and return value for which button was selected CALL diacase(button%,flag%) :REM Pass button selection to case statement. WEND :REM If user selects OK or Cancel While loop exits IF button% = 1 THEN :REM User selected OK so print array contents ? "CHOSEN FIELDS" CALL prnt(Dispbox$(),x%) END IF REMOVE DIALOG "FieldSelect" :REM Remove dialog from memory END SUB END :REM End program REM******************************************************************************** REM Init REM Dimension arrays used by dialog box as global. When the dialog box is called it will display the REM values of Listbox$() in the left window and Dispbox$() in the right window. Selection$() and REM Selection2$() represent values selected from these two windows. The last statement fills the REM array Listbox$() with the field names from the current file. REM******************************************************************************** SUB init() GLOBAL x% x% = FILEINFO ( FILE ,1) :REM Store number of fields in the file for array dimensions GLOBAL Listbox$(x%),Selection$(x%),Dispbox$(x%),Selection2$(x%) FILLARRAY Listbox$,1 :REM Fills array with field from open file END SUB REM******************************************************************************** REM Diacase REM This routine receives button% which represents which button the user selected in the dialog box. REM The case statement evaluates the variable and calls the proper routine. Flag% is passed back to REM main it signal whether the user wants to continue or exit. REM******************************************************************************** SUB diacase(button%,flag%) SELECT CASE button% CASE 0 :REM Cancel selected flag% = 1 :REM set flag to exit CASE 1 :REM OK selected flag% = 1 :REM set flag to exit CASE 2 :REM Clear selected CALL empty(Dispbox$(),x%) :REM Empty arrays back to their original state FILLARRAY Listbox$,1 :REM Refill list array with field names. CASE 3 :REM Insert selected :REM Insert selected values into 2nd window & remove from current CALL switch(Listbox$(),Dispbox$(),Selection$(),x%) CASE 4 :REM Insert All selected FILLARRAY Dispbox$,1 :REM Fill 2nd list box array with field values CALL empty(ListBox$(),x%) :REM Remove all values from original array CASE 5 :REM Delete selected :REM Opposite of Insert. We are just moving values the other way CALL switch(Dispbox$(),Listbox$(),Selection2$(),x%) END SELECT END SUB REM******************************************************************************** REM Created dialog box in memory REM Once this routine has created the dialog box in memory it can be displayed by the statement: REM DIALOG "FieldSelet", button%. This statement is executed in SUB main(). REM******************************************************************************** SUB diafs() CREATE DIALOG "FieldSelect",0,0,225,104,"Field Selection","System",10 ADD DIALOG "FieldSelect",5,2,3,52,9,0,"&Fields" ADD DIALOG "FieldSelect",5,144,3,77,9,0,"&Selected fields" ADD DIALOG "FieldSelect",7,2,11,77,65,8,2,Listbox$,Selection$ ADD DIALOG "FieldSelect",1,85,12,53,15,0,"&Insert",3,1 ADD DIALOG "FieldSelect",7,143,12,77,65,8,2,Dispbox$,Selection2$," " ADD DIALOG "FieldSelect",1,85,38,53,15,0,"Insert &all",4,1 ADD DIALOG "FieldSelect",1,86,64,53,15,0,"&Delete",5,1 ADD DIALOG "FieldSelect",1,42,84,40,15,0,"OK",1,1 ADD DIALOG "FieldSelect",1,92,84,40,15,0,"Clear",2,1 ADD DIALOG "FieldSelect",1,143,85,40,15,0,"Cancel",0,0 END SUB REM******************************************************************************** REM Array Functions and Subroutines REM******************************************************************************** REM******************************************************************************** REM Prnt REM This routine prints the contents of an array. It receives the array and the dimensions of the array REM as parameters. *Remember when you dimension an array with 5 elements you get 6. Array(0) REM through array(5) REM******************************************************************************** SUB prnt(array$(),dm%) FOR i% = 0 TO dm% ? array$(i%) NEXT i% END SUB REM******************************************************************************** REM Size% REM This function finds the last element of the array that contains a non-blank value. The function is REM used when data is being added to an array. It insures that the new data is added to the end of the REM array not over existing data. REM A WHILE loop is executed until a blank element in the array is found. It would probably be a REM good idea to check for going out of bounds on the array but in this program that situation will REM ever happen. REM******************************************************************************** FUNCTION size%(array$()) WHILE array$(pointer%) <> "" pointer% = pointer% + 1 WEND size% = pointer% END FUNCTION REM******************************************************************************** REM Empty REM This procedure clears the contents of an array. It accepts the array and the dimensions of the REM array. A FOR loop assigns an empty value to every element of the array. REM******************************************************************************** SUB empty(array$(),dm%) FOR i% = 0 TO dm% array$(i%) = "" NEXT i% END SUB REM******************************************************************************** REM Copy REM This procedure makes a copy of an array. The procedure receives an array, frst$, and its REM dimensions, dm% . It then passes back a copy of the array, cpy$. REM******************************************************************************** SUB cpy(frst$(),cpy$(),dm%) FOR i% = 0 TO dm% cpy$(i%) = frst$(i%) NEXT i% END SUB REM******************************************************************************** REM Squash REM This procedure removes blank spaces from an array by moving all data to the first elements of REM the array - it squashes it. This procedure is required because when a dialog list displays array REM information it will terminate the display at the first null string ("") value it finds. REM REM This routine could be executed more elegantly by using pointers and manipulating the array REM directly. This approach was chosen for simplicities sake. REM******************************************************************************** SUB squash(array$()) DIM temp$(x%) :REM Make a temporary array for storing data j% = 0 FOR i% = 0 TO x% REM If the array element contains a value copy it to the temporary array. IF array$(i%) <> "" THEN temp$(j%) = array$(i%) j% = j% + 1 END IF NEXT i% CALL cpy(temp$(),array$(),x%) :REM Copy the temporary array back to the original array. END SUB REM******************************************************************************** REM Switch REM This routine looks at the elements in array sel$() and adds them to receive$() and removes them REM from give$(). The idea being that we want to take the values a user has selected, whether it be REM from the Fields list box or the Selected fields list box, and move them to the opposite window REM while removing them from the current window. REM dm% contains the dimension of these arrays. REM******************************************************************************** SUB switch(give$(),receive$(),sel$(),dm%) ptr% = size%(receive$()) :REM size% is a user defined function that returns the last element in REM an array that contains a value. REM While there are values in the selection array and the pointer is within array dimensions WHILE sel$(i%) <> "" AND ptr% <= dm% receive$(ptr%) = sel$(i%) :REM Copy the value from sel$ to receive$ array FOR j% = 0 TO dm% IF give$(j%) = sel$(i%) THEN give$(j%) = "" :REM Find value from sel$ in give$ and remove it NEXT j% ptr% = ptr% + 1 :REM Increment pointers i% = i% + 1 WEND CALL squash(give$()) :REM remove the blank elements of the array CALL empty(Sel$(),x%) :REM empty the selection array END SUB REM******************************************************************************** REM Error checking routine REM REM If an error occurs this routine checks the ERRNO. If the error is number 44 "No File Selected" REM then a REQUEST box displays allowing the user to select a file to be opened. The REQUEST REM statement passes this file name to the OPEN FILE statement. Once the file has been opened the REM program resumes to where the error occurred. In this case the FILEINFO statement in SUB REM init ()would be the culprit. REM REM If the error is not 44 then the error message is displayed and the program ends. REM******************************************************************************** errcheck: IF ERRNO = 44 THEN :REM No file was selected b$ = "*.SBF" :REM Set a filter and present the user with a File Selection request REQUEST "You must open a file first!","",26,bt%,b$ OPEN FILE b$ RESUME :REM Re execute code that caused the error. ELSE REMOVE DIALOG "FieldSelect" REQUEST "Error occurred", ERR$ ( ERRNO ),0 END END IF Program: Superbase Versions: 2.x Date: September 9, 1993 D Date: