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