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

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.

Multi-column menu

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

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

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

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


GoStats stats counter