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.