Creating user friendly programs Creating user friendly programs Part 7 Part 7 by Steven Flintham (15A) Interacting with the user (4) As mentioned in the previous issue, in this article I intend to start covering some of the other ways of accepting user input. Inevitably, there will be some overlap between these articles and the previous ones about menus. For instance, you may wish to check that the user really does intend to perform a potentially damaging operation with a prompt such as: Are you sure? (Y/N) In this case, where a single key response is required, the same precautions should be taken as for single key response in a direct choice menu. The accompanying program FillIn demonstrates a relatively uncommon (in my experience) form of input. When run it will display a list of possible choices and invite you to type one in. As you type, it will 'predict' the choice you want, disallowing any key presses which would not match one of the possible options. I would suggest that you play around with the program a bit to see how it handles various inputs. The routine itself is FNfill_in(choices%,allow_null%) - the rest of the program exists only to provide a demonstration of the routine. Before calling it, the choices should be stored in the first choices% elements of the array fill_in$(). allow_null% should be TRUE if the routine should allow you to press RETURN without a choice - try changing line 160 in FillIn to see the effect. Notice how the routine handles situations where one possible choice is a shortened version of another - this happens in FillIn with both Number/Num and Print/Printout. If NUM is typed, the program must treat this as Num rather than Number, since it is impossible to type in more characters in to identify this option. The routine handles this, but if the longer option comes first (as happens with Number, but not with Printout) the shorter one will only appear when it has been completely typed in. This gives a result as follows: Key pressed Complete entry Choice N N Number U NU Number M NUM Num B NUMB Numb This might seem somewhat illogical, and it could have been avoided by having the program sort the options into length order where appropriate. However, I felt that a programmer using this routine might have some good reason for preferring the options to be chosen in the order in which they occur in the list. The above situation can be avoided by placing Num before Number in the list - this was not done here in order to demonstrate the situation. When it is called, the routine records the current position of the cursor, sets up a null string ready to hold the user's input and reads through the list of choices to find the longest (lines 640 to 690). This is done simply for use when deleting the displayed choice later on. It then obtains a valid keypress (lines 710-750), changing any lower case input to upper case as it does so. If appropriate, the keypress is added to the user input held in user$ (line 760) or if DELETE has been pressed, a character is removed from the user input (line 770). The routine then checks to see if the user input matches the start of any of the possible choices (lines 780-820). Line 810 checks to see if the user's input matches the same number of characters from the left of each possible choice, ignoring the case of the strings. Note that a match is only recorded if no previous match has been found (match%=-1) AND the user has typed something in (user$<>""). The first of these is ensures that where two choices match, the one first in the fill_in$() array will be used. The second avoids a situation where everything matches because the user has not yet typed anything in - the leftmost 0 zero characters of any string are ""! Line 800 provides the facility described above for forcing a match if a shorter choice is also contained at the start of a longer one. If the user's input exactly matches a possible choice (ignoring case), it sets match% immediately, preventing line 810 from setting match% if it later encounters another possible match. By line 830, match% will be -1 if no matches have been found or will be the subscript of the fill_in$() array containing the match. Line 830 deletes the last character in the line if no match was found, since the last key pressed was obviously not useful in finding a match. Line 840 then either displays the match, placing the cursor afterwards at the point where it would be if only the user's keypresses had been shown, or removes anything displayed if no match was found, leaving the cursor at the point where any matches will be displayed. The cursor is used like this because it shows the user how much has been typed in and how much has been 'guessed' - especially important if a key has been pressed which caused no matches to be found and was therefore removed by line 830. Try removing the final TABs on this line so that it reads: 840IF match%<>-1 THEN PRINTTAB(pos%, vpos%);fill_in$(match%);SPC(longest% -LEN(fill_in$(match%))); ELSE PRINTTAB(pos%,vpos%);SPC(longest%); and see if you think the routine is less user friendly. Line 850 simply forces the routine to repeat until RETURN is pressed and, if appropriate, a match has been found. Line 860 currently returns either a null if this is permitted to get through the check in line 850 or the actual string matched. If you want to use the routine in your own programs, you might prefer to modify it to return -1 for no match or the subscript of the fill_in$() array: 860=match% FNto_upper is a standard upper case conversion routine which is used by FNfill_in. It must therefore be present in some form or another if you wish to use FNfill_in in your own programs, but you could write your own version of FNto_upper if you prefer. It takes the old string as a parameter and returns it with any lower case characters converted to upper case. Everything else is left exactly as found, so FNto_upper("Testing, testing, 1, 2, 3!") will return: TESTING, TESTING, 1, 2, 3! As always, you are free to use the routine in your own programs provided they are not sold for profit. In the next article, I intend to cover some of the more familiar ways of accepting user input and how to make sure that they are as user friendly as possible.