HomePage | | Optical Illusions | War Stories | QBasic | Dads Navy Days | Bristol | Bristol, USA | Bristol, Canada | Terre Haute | Miscellany | Web Stuff | About Ray | Site Map | Site Search | Messages | Credits | Links | Web Rings
QBasic | Errors | 40lb Weight | Bits | Chance | Colours | Dates | Delays | File Dialog | Files | Input | Matching | Menus | Mouse | Numbers | SeqNo | SIRDS | Sorts | Text | Timer | DLoads
A simple text menu

A simple text menu
One of the simplest menus to make is the menu above. The user is simply asked for a number, or letter, corresponding to what they want to do. The code is easy and is shown below.
'TxtMenu.bas Ray Thomas February 2002
'Declare the variables (not strictly needed for INTEGERS or STRINGS)
DIM MenuIn AS INTEGER 'Numeric for user main menu input
DO
GOSUB MainMenu 'Call the main menu
SELECT CASE MenuIn
CASE 1
GOSUB AddRec 'Add a record
CASE 2
GOSUB DelRec 'Delete a record
CASE 3
GOSUB ModRec 'Modify a record
CASE 4
GOSUB SrchRec 'Search for a record
CASE 5
GOSUB PrnRec 'Print a record
CASE 6
GOSUB ShwRec 'Displays the records
END SELECT
LOOP UNTIL MenuIn = 7
CLOSE 'Close any open files
END 'End of program
MainMenu:
CLS
PRINT
PRINT "What do you want to do"
PRINT "**********************"
PRINT "1. Add a record"
PRINT "2. Delete a record"
PRINT "3. Modifiy a record"
PRINT "4. Search database"
PRINT "5. Print a report"
PRINT "6. Display all records"
PRINT "7. Quit the program"
PRINT
PRINT "Please press the number of your choice..."
PRINT
PRINT "(7 will exit the program)"
PRINT
INPUT "What is your Selection? ", MenuIn
RETURN
AddRec:
RETURN
DelRec:
RETURN
ModRec:
RETURN
SrchRec:
RETURN
PrnRec:
RETURN
ShwRec:
RETURN
A simple menu

Here is the code :-
'Menu.bas Ray Thomas February 2002
OPTION BASE 1
DIM MenuItem(3) AS STRING 'Define the menu item array
DIM ChooseItem AS INTEGER 'Currently chosen menu item
DIM XMenuPosn AS INTEGER 'Controls the menu item X positions
DIM YMenuPosn AS INTEGER 'Controls the menu item Y positions
MenuItem$(1) = " Alpha "
MenuItem$(2) = " Bravo "
MenuItem$(3) = " Charlie "
CLS
ChooseItem = 1
XMenuPosn = 10
YMenuPosn = 3
GOSUB DrawMenu
'get cursor key movements and redraw menu
DO
Cmmnd$ = INKEY$
IF LEN(Cmmnd$) = 2 THEN Cmmnd$ = RIGHT$(Cmmnd$, 1)
IF Cmmnd$ = "8" OR Cmmnd$ = CHR$(72) THEN GOSUB MoveUp
IF Cmmnd$ = "2" OR Cmmnd$ = CHR$(80) THEN GOSUB MoveDown
IF Cmmnd$ = "7" OR Cmmnd$ = CHR$(71) THEN ChooseItem = 1
IF Cmmnd$ = "1" OR Cmmnd$ = CHR$(79) THEN ChooseItem = UBOUND(MenuItem)
GOSUB DrawMenu
LOOP UNTIL Cmmnd$ = CHR$(13)
PRINT
COLOR 16, 10
PRINT "Item chosen ="; MenuItem(ChooseItem)
END
DrawMenu:
'Draw the menu
LOCATE YMenuPosn, XMenuPosn
FOR Count = 1 TO UBOUND(MenuItem$)
IF Count = ChooseItem THEN COLOR 4, 2 ELSE COLOR 2, 4
PRINT MenuItem$(Count)
LOCATE CSRLIN, XMenuPosn
NEXT Count
RETURN
MoveUp:
IF ChooseItem = 1 THEN
ChooseItem = UBOUND(MenuItem$)
ELSE
ChooseItem = ChooseItem - 1
END IF
RETURN
MoveDown:
IF ChooseItem = UBOUND(MenuItem$) THEN
ChooseItem = 1
ELSE
ChooseItem = ChooseItem + 1
END IF
RETURN
The up / down arrows on the keypad move the highlighted text up and down. With the Home key will highlight the first text and the End key the last. When Enter is pressed the program will display which text was high-lighted at the time.
Multi-column text menu
In January 2002, I received an email from someone who wanted to know how to implement a multi-column menu containing 60 menu items. I wasn't sure if all would fit onto the screen but it does. I've also tried to write it in such a way that the programmer can easily alter the way the menu looks by changing the number of columns, the column widths etc. This version does not care whether the NumLock key is on or off, it will work either way.

Screenshot of the multi-column menu
'Menucol.bas Ray Thomas January 2002
OPTION BASE 1
DIM MenuItem(60) AS STRING * 15 'Define the menu item array
DIM ChooseItem AS INTEGER 'Currently chosen menu item
DIM XMenuPosn AS INTEGER 'Controls the menu item X positions
DIM YMenuPosn AS INTEGER 'Controls the menu item Y positions
DIM Count AS INTEGER 'Array counter
DIM MenuLine AS INTEGER 'Number of menu items per line
DIM Temp AS STRING 'Used to centre text in the space
DATA Choice 1, Choice 2, Choice 3, Choice 4, Choice 5
DATA Choice 6, Choice 7, Choice 8, Choice 9, Choice 10
DATA Choice 11, Choice 12, Choice 13, Choice 14, Choice 15
DATA Choice 16, Choice 17, Choice 18, Choice 19, Choice 20
DATA Choice 21, Choice 22, Choice 23, Choice 24, Choice 25
DATA Choice 26, Choice 27, Choice 28, Choice 29, Choice 30
DATA Choice 31, Choice 32, Choice 33, Choice 34, Choice 35
DATA Choice 36, Choice 37, Choice 38, Choice 39, Choice 40
DATA Choice 41, Choice 42, Choice 43, Choice 44, Choice 45
DATA Choice 46, Choice 47, Choice 48, Choice 49, Choice 50
DATA Choice 51, Choice 52, Choice 53, Choice 54, Choice 55
DATA Choice 56, Choice 57, Choice 58, Choice 59, Choice 60
ChooseItem = 1 'Starting point of highlighted menu item
XMenuPosn = 10 'X starting point of menu
YMenuPosn = 3 'Y starting point of menu
MenuLine = 4 'Number of columns in the menu
'*** Fill the MenuItme Array ***
FOR Count = 1 TO UBOUND(MenuItem$)
READ Temp$
'*** Centre the Text ***
Temp$ = SPACE$((15 - LEN(Temp$)) / 2) + Temp$
MenuItem(Count) = Temp$
NEXT Count
CLS
GOSUB DrawMenu
'*** get cursor key movements and redraw menu ***
DO
Cmmnd$ = INKEY$
IF LEN(Cmmnd$) = 2 THEN Cmmnd$ = RIGHT$(Cmmnd$, 1)
IF Cmmnd$ = "8" OR Cmmnd$ = CHR$(72) THEN GOSUB MoveUp
IF Cmmnd$ = "2" OR Cmmnd$ = CHR$(80) THEN GOSUB MoveDown
IF Cmmnd$ = "4" OR Cmmnd$ = CHR$(75) THEN GOSUB Moveleft
IF Cmmnd$ = "6" OR Cmmnd$ = CHR$(77) THEN GOSUB MoveRight
IF Cmmnd$ = "9" OR Cmmnd$ = CHR$(73) THEN GOSUB TopCol
IF Cmmnd$ = "3" OR Cmmnd$ = CHR$(81) THEN GOSUB BottomCol
IF Cmmnd$ = "7" OR Cmmnd$ = CHR$(71) THEN ChooseItem = 1
IF Cmmnd$ = "1" OR Cmmnd$ = CHR$(79) THEN ChooseItem = UBOUND(MenuItem$)
GOSUB DrawMenu
LOOP UNTIL Cmmnd$ = CHR$(13)
PRINT
COLOR 16, 10
PRINT "Item chosen ="; MenuItem(ChooseItem)
END:
DrawMenu:
'Draw the menu
LOCATE YMenuPosn, XMenuPosn
FOR Count = 1 TO UBOUND(MenuItem$)
IF Count = ChooseItem THEN COLOR 4, 2 ELSE COLOR 2, 4
PRINT MenuItem$(Count);
IF Count MOD MenuLine = 0 THEN
PRINT
LOCATE CSRLIN, XMenuPosn
END IF
NEXT Count
RETURN
MoveUp:
IF ChooseItem <= MenuLine THEN
ChooseItem = UBOUND(MenuItem$) - (MenuItem MOD MenuLine)
ELSE
ChooseItem = ChooseItem - MenuLine
END IF
RETURN
MoveDown:
IF ChooseItem > UBOUND(MenuItem$) - MenuLine THEN
ChooseItem = ChooseItem MOD MenuLine
ELSE
ChooseItem = ChooseItem + MenuLine
END IF
IF ChooseItem = 0 THEN ChooseItem = MenuLine
RETURN
Moveleft:
ChooseItem = ChooseItem - 1
IF ChooseItem = 0 THEN ChooseItem = UBOUND(MenuItem$)
RETURN
MoveRight:
ChooseItem = ChooseItem + 1
IF ChooseItem = UBOUND(MenuItem$) + 1 THEN ChooseItem = 1
RETURN
TopCol:
ChooseItem = ChooseItem MOD MenuLine
IF ChooseItem = 0 THEN ChooseItem = MenuLine
RETURN
BottomCol:
ChooseItem = UBOUND(MenuItem$) - (MenuLine - (ChooseItem MOD MenuLine))
IF MenuLine - (ChooseItem MOD MenuLine) = MenuLine THEN ChooseItem = UBOUND(MenuItem$)
RETURN
The way this menu is designed is so that the PgUp and PgDn key will take you to the top or bottom of the column the cursor is in, the Home key will go to the first menu item and the End key will take you to the last. The left or right arrow keys will move the highlighted choice one place to the left or to the right and the up and down arrow keys will move one item up or down the column.
Menu with shortcuts
Rather than using the arrow and keypad keys to navigate around the menu we could also provide the user a way of jumping to the menu item of their choice.

Menu with shortcuts - a screenshot of MenuAlt.bas
When you design a menu like this you may find you have to change the menu choices slightly as you may end up with multiple choices. For example, when I originally wrote this item 2 ("Remove a record") was called "Delete a record". This would have given the shortcut as Alt + D, which would have clashed with "Display all records"
'Menualt.bas Ray Thomas February 2002
OPTION BASE 1
DIM MenuItem(7) AS STRING * 25 'Define the menu item array
DIM ChooseItem AS INTEGER 'Currently chosen menu item
DIM XMenuposn AS INTEGER 'Controls the menu item X positions
DIM YMenuPosn AS INTEGER 'Controls the menu item Y positions
DIM Count AS INTEGER 'Array counter
DIM EndMenu AS INTEGER 'F, Enter or Alt keys pressed
DATA F1 - Add a record, F2 - Remove a record, F3 - Modify a record
DATA F4 - Search database, F5 - Print a report, F6 - Display all records
DATA F7 - Quit the program
ChooseItem = 1 'Starting point of highlighted menu item
XMenuposn = 20 'X starting point of menu
YMenuPosn = 6 'Y starting point of menu
'*** Fill the MenuItme Array ***
FOR Count = 1 TO UBOUND(MenuItem$)
READ MenuItem(Count)
NEXT Count
CLS
PRINT
PRINT " Use the Enter key to choose the highlighted menu item or"
PRINT " Press the F number key associated with the menu item or"
PRINT " Press the Alt key and the capitalised letter of the menu item"
GOSUB DrawMenu
'*** get cursor key movements and redraw menu ***
DO
Cmmnd$ = (INKEY$)
IF LEN(Cmmnd$) = 2 THEN Cmmnd$ = RIGHT$(Cmmnd$, 1)
IF Cmmnd$ = "8" OR Cmmnd$ = CHR$(72) THEN GOSUB MoveUp
IF Cmmnd$ = "2" OR Cmmnd$ = CHR$(80) THEN GOSUB MoveDown
IF Cmmnd$ = "7" OR Cmmnd$ = CHR$(71) THEN ChooseItem = 1
IF Cmmnd$ = "1" OR Cmmnd$ = CHR$(79) THEN ChooseItem = UBOUND(MenuItem)
IF Cmmnd$ = CHR$(13) THEN EndMenu = 1
IF Cmmnd$ = CHR$(59) OR Cmmnd$ = CHR$(30) THEN
ChooseItem = 1
EndMenu = 1
END IF
IF Cmmnd$ = CHR$(60) OR Cmmnd$ = CHR$(19) THEN
ChooseItem = 2
EndMenu = 1
END IF
IF Cmmnd$ = CHR$(61) OR Cmmnd$ = CHR$(50) THEN
ChooseItem = 3
EndMenu = 1
END IF
IF Cmmnd$ = CHR$(62) OR Cmmnd$ = CHR$(31) THEN
ChooseItem = 4
EndMenu = 1
END IF
IF Cmmnd$ = CHR$(63) OR Cmmnd$ = CHR$(25) THEN
ChooseItem = 5
EndMenu = 1
END IF
IF Cmmnd$ = CHR$(64) OR Cmmnd$ = CHR$(32) THEN
ChooseItem = 6
EndMenu = 1
END IF
IF Cmmnd$ = CHR$(65) OR Cmmnd$ = CHR$(16) THEN
ChooseItem = 7
EndMenu = 1
END IF
GOSUB DrawMenu
LOOP UNTIL EndMenu = 1
PRINT
COLOR 16, 10
PRINT "Item chosen = "; MenuItem(ChooseItem)
END
DrawMenu:
'Draw the menu
LOCATE YMenuPosn, XMenuposn
FOR Count = 1 TO UBOUND(MenuItem$)
IF Count = ChooseItem THEN COLOR 4, 2 ELSE COLOR 2, 4
LOCATE CSRLIN, XMenuposn
PRINT MenuItem$(Count)
NEXT Count
RETURN
MoveUp:
IF ChooseItem = 1 THEN
ChooseItem = UBOUND(MenuItem$)
ELSE
ChooseItem = ChooseItem - 1
END IF
RETURN
MoveDown:
IF ChooseItem = UBOUND(MenuItem$) THEN
ChooseItem = 1
ELSE
ChooseItem = ChooseItem + 1
END IF
RETURN
Horizontally scrolling menu

Screenshot of my Horizontally Scrolling Menu
What this program does is create a menu where only a proportion of the menu items can be seen at one time. This is idea for those times when you have a large menu to display, or only limited space. The program itself is very flexible, as you can change the number of rows and columns that are displayed. If you don't feel like editing it yourself you can use it "as is", all you have to do is supply the array of the menu items.
The characters in front of the menu items are placed there merely for convenience, I put them there to demonstrate a feature of the program. Instead of pressing one of the selection or navigation keys you press a character key, the program will search the menu item array and highlight the first item it finds beginning with that character.
Navigation is done with the arrow keys, Page up, Page Down, Home and End keys. Selection is made by pressing enter and you can can quit the program by pressing the Esc key.
'HMenu Ray Thomas March 2002
'A horizontally scrolling menu
OPTION BASE 1
DIM MenuArray(100) AS STRING * 15 'Contains the menu items
DIM Colmns AS INTEGER 'Number of columns in the menu
DIM Rows AS INTEGER 'Number of rows in the menu
DIM TotColmns AS INTEGER 'Total number of columns that can be made
DIM ColmnWid AS INTEGER 'Column width = Menu item width
DIM Gap AS INTEGER 'Gap between columns
DIM MenuItems AS INTEGER 'Number of items in the ManuArray
DIM MaxDisplay AS INTEGER 'Max number of menu items that can be displayed
DIM FirstItem AS INTEGER 'First menu item to be diplayed
DIM HiLiteItem AS INTEGER 'Menu item that is highlighted
DIM XMenuPosn AS INTEGER 'X position of the first menu item
DIM YMenuPosn AS INTEGER 'Y position of the first menu item
DIM XItemPosn AS INTEGER 'X position of columns
DIM UserIn AS STRING 'User input
DIM Count AS INTEGER 'Loop counter
'*** Although MenuArray has been dimensioned with 100 elements ***
'*** not all of them need be filled ***
'*** A standard length was chosen to make the columns of equal width
'*** 53 was chosen as it is a prime number, which should test the calculations ***
'*** Fill the array ***
'*** The CHR$(Count + 32) is here because I want a unique character in ***
'*** the menu items - it's another aid to navigation around the menu ***
FOR Count = 1 TO 53
MenuArray$(Count) = CHR$(Count + 32) + " Menu Item " + STR$(Count)
NEXT Count
'*** Inititialise the other variables ***
Rows = 10
Colmns = 3
MenuItems = 53
FirstItem = 1
HiLiteItem = 1
MaxDisplay = Rows * Colmns
XMenuPosn = 5
YMenuPosn = 5
TotColmns = FIX((MenuItems + (Rows - 1)) / Rows)
Gap = 5
ColmnDist = LEN(MenuArray$(1)) + Gap
CLS
DO
GOSUB DrawMenu '*** Draw the menu ***
GOSUB UserInput '*** Get the user input ***
LOOP UNTIL UserIn$ = CHR$(27) OR UserIn$ = CHR$(13)
LOCATE YMenuPosn + Rows + 3, XMenuPosn
IF UserIn$ = CHR$(27) THEN PRINT "ESC pressed"
IF UserIn$ = CHR$(13) THEN PRINT "Selected menu item = "; MenuArray(HiLiteItem)
END
DrawMenu:
'*** Draw the menu - obviously ***
XItemPosn = XMenuPosn
LOCATE YMenuPosn, XItemPosn
FOR Count = FirstItem TO FirstItem + MaxDisplay - 1
PRINT SPACE$(ColmnDist);
LOCATE CSRLIN + 1, XMenuPosn
IF Count MOD Rows = 0 THEN
XItemPosn = XItemPosn + ColmnDist
LOCATE YMenuPosn, XItemPosn
END IF
NEXT Count
XItemPosn = XMenuPosn
LOCATE YMenuPosn, XItemPosn
FOR Count = FirstItem TO FirstItem + MaxDisplay - 1
PRINT MenuArray$(Count);
LOCATE CSRLIN + 1, XItemPosn
IF Count MOD Rows = 0 THEN
XItemPosn = XItemPosn + ColmnDist
LOCATE YMenuPosn, XItemPosn
END IF
NEXT Count
IF HiLiteItem > FirstItem + MaxDisplay - 1 THEN
DO
FirstItem = FirstItem + Rows
LOOP UNTIL HiLiteItem < FirstItem + MaxDisplay
END IF
IF HiLiteItem < FirstItem THEN
DO
FirstItem = FirstItem - Rows
LOOP UNTIL HiLiteItem >= FirstItem
END IF
XItemPosn = XMenuPosn
LOCATE YMenuPosn, XItemPosn
FOR Count = FirstItem TO FirstItem + MaxDisplay - 1
PRINT MenuArray$(Count);
LOCATE CSRLIN + 1, XItemPosn
IF Count MOD Rows = 0 THEN
XItemPosn = XItemPosn + ColmnDist
LOCATE YMenuPosn, XItemPosn
END IF
NEXT Count
XItemPosn = XMenuPosn
XItemPosn = XMenuPosn
IF HiLiteItem > 1 THEN LOCATE YMenuPosn + ((HiLiteItem - FirstItem) MOD Rows), XItemPosn + (FIX((HiLiteItem - FirstItem) / Rows) * ColmnDist)
IF HiLiteItem = 1 THEN LOCATE YMenuPosn, XItemPosn
COLOR 0, 7
PRINT MenuArray$(HiLiteItem);
COLOR 7, 0
'*** Print the << and / or the >> ***
LOCATE YMenuPosn - 2, XMenuPosn
PRINT " "
LOCATE YMenuPosn - 2, XMenuPosn + ((Colmns * ColmnDist) - Gap - 2)
PRINT " "
IF FirstItem > Rows THEN
LOCATE YMenuPosn - 2, XMenuPosn
PRINT "<<"
END IF
IF FirstItem < MenuItems - MaxDisplay THEN
LOCATE YMenuPosn - 2, XMenuPosn + ((Colmns * ColmnDist) - Gap - 2)
PRINT ">>"
END IF
RETURN
UserInput:
'*** Get and process the user input ***
UserIn$ = "" '*** Reset UserIn$ ***
DO
UserIn$ = INKEY$
LOOP UNTIL UserIn$ <> ""
SELECT CASE UserIn$
CASE CHR$(0) + CHR$(80) '*** Down arrow pressed ***
IF HiLiteItem < MenuItems THEN HiLiteItem = HiLiteItem + 1
CASE CHR$(0) + CHR$(72) '*** Up arrow pressed ***
IF HiLiteItem - 1 <> 0 THEN HiLiteItem = HiLiteItem - 1
CASE CHR$(0) + CHR$(75) '*** Left arrow pressed ***
IF HiLiteItem > Rows THEN HiLiteItem = HiLiteItem - Rows
CASE CHR$(0) + CHR$(77) '*** Right arrow pressed ***
IF HiLiteItem < (TotColmns - 1) * Rows + 1 THEN HiLiteItem = HiLiteItem + Rows
IF HiLiteItem > MenuItems THEN HiLiteItem = MenuItems
CASE CHR$(0) + CHR$(71) '*** Home pressed ***
HiLiteItem = 1
CASE CHR$(0) + CHR$(79) '*** End pressed ***
HiLiteItem = MenuItems
CASE CHR$(0) + CHR$(73) '*** Page Up pressed ***
IF HiLiteItem > MaxDisplay THEN
HiLiteItem = HiLiteItem - MaxDisplay
ELSE
HiLiteItem = 1
END IF
CASE CHR$(0) + CHR$(81) '*** Page Down pressed ***
IF HiLiteItem < MenuItems - MaxDisplay THEN
HiLiteItem = HiLiteItem + MaxDisplay
ELSE
HiLiteItem = MenuItems
END IF
CASE ELSE
'*** For any other key press find the first menu item ***
'*** starting with that key ***
FOR Count = 1 TO MenuItems
IF LEFT$(MenuArray$(Count), 1) = UserIn$ THEN
HiLiteItem = Count
EXIT FOR
END IF
NEXT Count
END SELECT
RETURN
You can always change the appearance of this menu to a vertically scrolling menu by making the number of rows longer and decreasing the number of columns to 1 or 2. You may also prefer to change the "<<" and ">>" to vertical arrows by replacing the code that prints them to PRINT CHR$(24);CHR$(24) and PRINT CHR$(25);CHR$(25) respectively. This will give you :-

HMenu as a vertically scrolling menu
Knowing the keyboard return codes for the cursor and function keys can be very useful, see Input for more details.
The menu programs are all available for download on my DLoads page.
QBasic | Errors | 40lb Weight | Bits | Chance | Colours | Dates | Delays | File Dialog | Files | Input | Matching | Menus | Mouse | Numbers | SeqNo | SIRDS | Sorts | Text | Timer | DLoads
HomePage | Optical Illusions | War Stories | QBasic | Dads Navy Days | Bristol | Bristol, USA | Bristol, Canada | Terre Haute | Miscellany | Web Stuff | About Ray | Site Map | Site Search | Messages | Credits | Links | Web Rings