I am trying to create a sub menu from a main menu, but I am struggling to figure out how to do so correctly

292 views Asked by At

I am creating a program that has a main menu that when you choose an option lets say 1, will take you to a sub menu which allows you to choose another option, lets say 1 again.

I am not able to figure out how to connect to get to the sub menu.

 int main()
 {
  
 sqlite3 *db;
 int rc;
 
 rc = sqlite3_open_v2("test.db", &db, SQLITE_OPEN_READWRITE, NULL);
 if (rc != SQLITE_OK)
     {
 cout << "Error opening database: " << sqlite3_errmsg(db) <<  endl;
 sqlite3_close(db);
 return 0;
     }
 else
     {
 cout << "Database opened successfully." <<  endl;
     }
 
 
 cout << "Welcome to Database" <<  endl;
 
 
 int choice = mainMenu();
 
 while (true)
         {
 switch (choice){
 
   
 case 1:
 addMenu();
 break;
 case 2:
 updateMenu();
 break;
 case 3:
 deleteCustomer(db);
 break;
 case -1:
 return 0;
 default:
 cout << "That is not a valid choice." <<  endl;
 cout << "\n\n";
 choice = mainMenu();
             }
         }
 sqlite3_close(db);//closes the database
 return 0;
 }
 
 void printMainMenu()
 {
 cout << "Please choose an option (enter -1 to quit):  " << endl;
 cout << "1. Add" << endl;
 cout << "2. Update" << endl;
 cout << "3. Delete" << endl;
 cout << "4. Make a transaction" << endl;
 cout << "Enter choice: ";
 }
 int mainMenu()
 {
 int choice = 0;
 
 printMainMenu();
 cin >> choice;
 while ((!cin || choice < 1 || choice > 4) && choice != -1)
     {
 if (!cin)
         {
 resetStream();
         }
 cout << "That is not a valid choice." << endl
 endl;
 printMainMenu();
 cin >> choice;
     }
 return choice;
 }
 
 void addMenu()
 {
 cout << "Please choose an option (enter -1 to quit):  " << endl;
 cout << "1. Add customer" << endl;
 cout << "2. Add product" << endl;
 cout << "Enter choice: ";
 
 }
1

There are 1 answers

0
tbxfreeware On
The Add Menu is typical

You are on the right track. Each menu runs a loop, and each menu item corresponds to a function that carries out its actions. Sometimes that means calling a function that is a "sub-menu"; other times that means calling a function that does more than that.

Inside the loop, you display the menu, and input the user's choice. A switch statement, based on the user's choice, selects which function to call.

The Add Menu from the OP is a typical example.

bool add_menu()
{
    char const* const menu
    {
        "Add Menu"
        "\n"
        "\n0. Quit"
        "\n1. Add customer"
        "\n2. Add product"
        "\n\n"
    };
    enum : int { Quit, Add_Customer, Add_Product };
    bool done{ false };
    do
    {
        std::cout << menu;
        int choice;
        tbx::cpp17::console::get_int("Choice? ", choice, 0, 2, false);
        std::cout << "\n\n";
        switch (choice)
        {
        case Quit:
            done = true;
            break;
        case Add_Customer:
            done = add_customer();
            break;
        case Add_Product:
            done = add_product();
            break;
        default:
            std::unreachable();
        }
    } while (!done);
    return false;  // Not `done` with Main Menu.
}

Function add_menu uses an enum to dress-up the switch statement. It also uses std::unreachable, a C++23 feature that is typically optimized away in release buids, but which translates into something like assert(false) in debug builds.

The only tricky part is the return value. The return value from one menu function becomes the done flag in the caller. When you return true, that sets the done flag in the caller.

Each of the menus in the program below returns false. That causes the corresponding parent menu to be redisplayed. Were a menu function to return true, that would cause the parent menu to be exited, without being redisplayed.

The other thing that streamlines the menu functions is function get_int.

Function get_int handles keyboard input

Function get_int is a robust routine that handles input from std::cin. It protects against all the usual errors that happen with std::cin. Because it uses std::getline for all keyboard input, it won't cause cin to fail when the user accidentally enters non-numeric data. It also performs range checks on the numbers that are entered, rejecting any that are out of range. It even has a cancel feature that allows the user to abort an input operation by pressing Enter on a blank line.

Note, however, that the cancel option can be disabled, which was done in all of the menus used here.

A call to get_int can have only two outcomes: 1. A valid, in-range integer is input, or 2. the user cancels. get_int returns true when a number is successfully entered, and false when the user cancels. The entered number is returned via a reference parameter (variable choice in the example below).

        // Valid choices range between 0 and 2.
        // The `cancel_is_allowed` flag is set to `false`.
        int choice;
        tbx::cpp17::console::get_int("Choice? ", choice, 0, 2, false);

Here is the declaration for function get_int. Complete source code, along with a detailed explanation of how it works, can be found in this StackOverflow answer.

// tbx.cpp17.utility-console.get_int.h
#ifndef TBX_CPP17_UTILITY_CONSOLE_GET_INT_H
#define TBX_CPP17_UTILITY_CONSOLE_GET_INT_H
#include <iostream>
#include <limits>
#include <string>
namespace tbx::cpp17::console
{
    bool get_int(
        std::string const& prompt,
        int& value,
        int const min = std::numeric_limits<int>::min(),
        int const max = std::numeric_limits<int>::max(),
        bool const cancel_is_allowed = true,
        std::istream& ist = std::cin,
        std::ostream& ost = std::cout);
}
#endif
// end file: tbx.cpp17.utility-console.get_int.h
A complete program

The following program demonstrates the menu functions in action.

// main.cpp
#include <iostream>
#include <utility>
#include "tbx.cpp17.utility-console.get_int.h"

// Functions are defined in the same order as these declarations.
bool main_menu();

bool add_menu();
bool add_customer();
bool add_product();

bool update_menu();
bool update_customer();
bool update_product();

bool delete_menu();
bool delete_customer();
bool delete_product();

bool transaction_menu();

int main()
{
    main_menu();
    return 0;
}

bool main_menu()
{
    char const* const menu
    {
        "Main Menu"
        "\n"
        "\n0. Quit"
        "\n1. Add"
        "\n2. Update"
        "\n3. Delete"
        "\n4. Make a transaction"
        "\n\n"
    };
    enum : int { Quit, Add, Update, Delete, Transaction };
    bool done{ false };
    do
    {
        std::cout << menu;
        int choice;
        tbx::cpp17::console::get_int("Choice? ", choice, 0, 4, false);
        std::cout << "\n\n";
        switch (choice)
        {
        case Quit:
            done = true;
            break;
        case Add:
            done = add_menu();
            break;
        case Update:
            done = update_menu();
            break;
        case Delete:
            done = delete_menu();
            break;
        case Transaction:
            done = transaction_menu();
            break;
        default:
            std::unreachable();
        }
    } while (!done);
    return false;  // Return value is discarded by function `main`.
}

bool add_menu()
{
    char const* const menu
    {
        "Add Menu"
        "\n"
        "\n0. Quit"
        "\n1. Add customer"
        "\n2. Add product"
        "\n\n"
    };
    enum : int { Quit, Add_Customer, Add_Product };
    bool done{ false };
    do
    {
        std::cout << menu;
        int choice;
        tbx::cpp17::console::get_int("Choice? ", choice, 0, 2, false);
        std::cout << "\n\n";
        switch (choice)
        {
        case Quit:
            done = true;
            break;
        case Add_Customer:
            done = add_customer();
            break;
        case Add_Product:
            done = add_product();
            break;
        default:
            std::unreachable();
        }
    } while (!done);
    return false;  // Not `done` with Main Menu.
}

bool add_customer()
{
    std::cout << "Add Customer\n\n";
    std::cout << "Under construction - Press Enter to continue...";
    std::string press_enter;
    std::getline(std::cin, press_enter);
    std::cout << "\n\n";
    return false;  // Not `done` with Add Menu.
}

bool add_product()
{
    std::cout << "Add Product\n\n";
    std::cout << "Under construction - Press Enter to continue...";
    std::string press_enter;
    std::getline(std::cin, press_enter);
    std::cout << "\n\n";
    return false;  // Not `done` with Add Menu.
}
bool update_menu()
{
    char const* const menu
    {
        "Update Menu"
        "\n"
        "\n0. Quit"
        "\n1. Update customer"
        "\n2. Update product"
        "\n\n"
    };
    enum : int { Quit, Update_Customer, Update_Product };
    bool done{ false };
    do
    {
        std::cout << menu;
        int choice;
        tbx::cpp17::console::get_int("Choice? ", choice, 0, 2, false);
        std::cout << "\n\n";
        switch (choice)
        {
        case Quit:
            done = true;
            break;
        case Update_Customer:
            done = update_customer();
            break;
        case Update_Product:
            done = update_product();
            break;
        default:
            std::unreachable();
        }
    } while (!done);
    return false;  // Not `done` with Main Menu.
}

bool update_customer()
{
    std::cout << "Update Customer\n\n";
    std::cout << "Under construction - Press Enter to continue...";
    std::string press_enter;
    std::getline(std::cin, press_enter);
    std::cout << "\n\n";
    return false;  // Not `done` with Update Menu.
}

bool update_product()
{
    std::cout << "Update Product\n\n";
    std::cout << "Under construction - Press Enter to continue...";
    std::string press_enter;
    std::getline(std::cin, press_enter);
    std::cout << "\n\n";
    return false;  // Not `done` with Update Menu.
}

bool delete_menu()
{
    char const* const menu
    {
        "Delete Menu"
        "\n"
        "\n0. Quit"
        "\n1. Delete customer"
        "\n2. Delete product"
        "\n\n"
    };
    enum : int { Quit, Delete_Customer, Delete_Product };
    bool done{ false };
    do
    {
        std::cout << menu;
        int choice;
        tbx::cpp17::console::get_int("Choice? ", choice, 0, 2, false);
        std::cout << "\n\n";
        switch (choice)
        {
        case Quit:
            done = true;
            break;
        case Delete_Customer:
            done = delete_customer();
            break;
        case Delete_Product:
            done = delete_product();
            break;
        default:
            std::unreachable();
        }
    } while (!done);
    return false;  // Not `done` with Main Menu.
}

bool delete_customer()
{
    std::cout << "Delete Customer\n\n";
    std::cout << "Under construction - Press Enter to continue...";
    std::string press_enter;
    std::getline(std::cin, press_enter);
    std::cout << "\n\n";
    return false;  // Not `done` with Delete Menu.
}

bool delete_product()
{
    std::cout << "Delete Product\n\n";
    std::cout << "Under construction - Press Enter to continue...";
    std::string press_enter;
    std::getline(std::cin, press_enter);
    std::cout << "\n\n";
    return false;  // Not `done` with Delete Menu.
}

bool transaction_menu()
{
    std::cout << "Make a Transaction\n\n";
    std::cout << "Under construction - Press Enter to continue...";
    std::string press_enter;
    std::getline(std::cin, press_enter);
    std::cout << "\n\n";
    return false;  // Not `done` with Main Menu.
}
// end file: main.cpp

Here is the output from a sample run:

Main Menu

0. Quit
1. Add
2. Update
3. Delete
4. Make a transaction

Choice? 1


Add Menu

0. Quit
1. Add customer
2. Add product

Choice? 3
3 is out of range. Please reenter.
Entries must be between 0 and 2.

Choice? 2


Add Product

Under construction - Press Enter to continue...


Add Menu

0. Quit
1. Add customer
2. Add product

Choice? 0


Main Menu

0. Quit
1. Add
2. Update
3. Delete
4. Make a transaction

Choice? 0