C++ 导航控制台菜单

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16852978/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 20:42:10  来源:igfitidea点击:

Navigating console menu

c++menuconsoledo-while

提问by fanatical

I'm totally new and I don't know how else to ask this or what to even search for.

我是全新的,我不知道还能怎么问这个问题,甚至不知道要搜索什么。

The case is this: I want to navigate through a menu with several sub-menus. In this example I'll just use "options" and a "game" to illustrate what I mean. Say you have a menu with 3 options.

情况是这样的:我想浏览带有多个子菜单的菜单。在这个例子中,我将只使用“选项”和“游戏”来说明我的意思。假设您有一个包含 3 个选项的菜单。

1 - Start

2 - Options

3 - Quit

1 - 开始

2 - 选项

3 - 退出

Choosing options should take you to another menu. Which would then look something like

选择选项应该会将您带到另一个菜单。然后看起来像

1 - Difficulty

2 - Sound

3 - Back

1 - 难度

2 - 声音

3 - 返回

Depending on where you go from here, there will be more sub menus obviously. I've tried nesting do-while loops and all kinds of things but I just don't have enough understanding to know what it is I'm doing wrong.

取决于你从这里去哪里,显然会有更多的子菜单。我试过嵌套 do-while 循环和各种事情,但我只是没有足够的理解来知道我做错了什么。

Here is what I have so far:

这是我到目前为止所拥有的:

#include <cstdlib>
#include <iostream>

using namespace std;

int main(int argc, char *argv[])
{
  int choice;

    do{
    cout << "Main Menu\n";
    cout << "Please make your selection\n";
    cout << "1 - Start game\n";
    cout << "2 - Options\n";
    cout << "3 - Quit\n";
    cout << "Selection: ";
    cin >> choice;

         switch(choice) {
           case 1:
             cout << "Pew pew!\n";
             break;
           case 2:
             cout <<"????\n";
             break;
           case 3:
             cout << "Goodbye!";
             break;
           default:
             cout << "Main Menu\n";
             cout << "Please make your selection\n";
             cout << "1 - Start game\n";
             cout << "2 - Options\n";
             cout << "3 - Quit\n";
             cout << "Selection: ";
             cin >> choice;    
         }
      } while(choice !=3);                            
    system("PAUSE");
    return EXIT_SUCCESS;
}

Which works like a regular menu. But I have no idea where to go from here. I consulted some books, but finding anything even remotely related to this was completely random. Any help or examples would be greatly appreciated.

这就像一个普通菜单。但我不知道从哪里开始。我查阅了一些书籍,但发现任何与此相关的东西都是完全随机的。任何帮助或示例将不胜感激。

What happened with nesting tons of loops just made all loops execute simultaneously every time. How do I keep this from happening? Making more choices? (choice1-2-3 etc ? or what?)

嵌套大量循环所发生的事情只会使所有循环每次都同时执行。我如何防止这种情况发生?做出更多选择?(选择 1-2-3 等?还是什么?)

采纳答案by max_

How about this (dunno if it compiles though):

这个怎么样(不知道是否可以编译):

     #include <cstdlib>
     #include <iostream>

     using namespace std;

     int GetInput()
     {
         int choice;    
        cin >> choice;
        return choice;
     }

     void DisplayMainMenu()
     {
     cout << "Main Menu\n";
         cout << "Please make your selection\n";
         cout << "1 - Start game\n";
         cout << "2 - Options\n";
         cout << "3 - Quit\n";
         cout << "Selection: ";
     }

     void DisplayOptionsMenu()
     {
         cout << "Options Menu\n";
         cout << "Please make your selection\n";
         cout << "1 - Difficulty\n";
         cout << "2 - Sound\n";
         cout << "3 - Back\n";
         cout << "Selection: ";
     }

     void Options()
     {
        int choice = 0;
        do
        {
            system("cls");
            DisplayOptionsMenu();
            choice = GetInput();
            switch(choice)
            {
                case 1:
                    cout << "difficulty stuff";
                    break;
                case 2:
                    cout << "sound stuff";
                    break;
                case 3:
                    break;
                default:
                    break;
            }
        } while(choice!=3);
     }

     int main(int argc, char *argv[])
     {
         int choice = 0;

         do
         {
            system("cls");
            DisplayMainMenu();
            choice = GetInput();
            switch(choice) {
                    case 1:
                            cout << "Pew pew!\n";
                            break;
                    case 2: 
                            Options();
                            break;
                    case 3: 
                            cout << "Goodbye!";
                            break;

                    default: 
                            break;
                   }
           } while(choice!=3);
         system("PAUSE");
         return EXIT_SUCCESS;
     }

回答by fanatical

Ok guys. Thanks for all the help. This is what I ended up with in the end. It runs as I want it to and by max_'s example and Mike B's commentary I think this works pretty well.

好,朋友们。感谢所有的帮助。这就是我最终得到的结果。它按照我想要的方式运行,根据 max_ 的示例和 Mike B 的评论,我认为这很有效。

Thanks alot everyone =)

非常感谢大家=)

#include <iostream>
#include <cstdlib>


using namespace std;

void menu();
void mainMenu();
void optionsMenu();
void options();
int choice1 = 0;
int choice2 = 3;

int main(int argc, char** argv) {



    menu();



    return 0;
}


void menu(){

        do {
        choice2 = 0;
        mainMenu();

        switch(choice1) {

            case 1:
                cout << "Pew pew!\n";
                break;

            case 2:
                options();
                break;

            case 3:
                break;

        }

    } while(choice1 != 3);


}

void options(void) {

    do {
        optionsMenu();

        switch(choice2){

            case 1:
                cout << "So difficult!\n";
                break;

            case 2: 
                cout << "Beep!\n";
                break;

            case 3:
                break;

            default: 
                break;

        }

    } while(choice2 != 3);


}




void mainMenu(void) {



    cout << "Main Menu\n";
    cout << "1 - Start game\n";
    cout << "2 - Options\n";
    cout << "3 - Quit\n";
    cout << "Please choose: ";
            cin >> choice1;

}

void optionsMenu(void) {



    cout << "Options Menu\n";
    cout << "1 - Difficulty\n";
    cout << "2 - Sound";
    cout << "3 - Back\n";
    cout << "Please choose: ";
            cin >> choice2;

}

回答by Mike B

I'd recommend that you change a few things here. Are you familiar with object-oriented design? If not, it's highly recommended that you read about that if you're looking to write code in C++ (Or just writing code in general, as it's a pretty major aspect of many programming languages)

我建议您在这里更改一些内容。你熟悉面向对象的设计吗?如果没有,强烈建议您阅读有关使用 C++ 编写代码的内容(或者只是编写一般代码,因为它是许多编程语言的一个非常重要的方面)

Consider treating each of your menus and submenus as individual objects. Each time you enter the loop, use an object pointer to call a method that prints the current menu text.

考虑将每个菜单和子菜单视为单独的对象。每次进入循环时,使用对象指针调用打印当前菜单文本的方法。

Then, take the input from the user as normal, and change the menu object you're using now.

然后,照常接受用户的输入,并更改您现在使用的菜单对象。

This is perhaps not the most ideal way to do a console menu, but it will give you a very strong grounding in how objected-oriented programming works.

这可能不是制作控制台菜单的最理想方式,但它会为您提供面向对象编程如何工作的坚实基础。

I've attached an example :

我附上了一个例子:

#include <iostream>
#include <string>

class BaseMenu
{
public:
    BaseMenu() { m_MenuText = "This shouldn't ever be shown!"; } // This is the constructor - we use it to set class-specific information. Here, each menu object has its own menu text.
    virtual ~BaseMenu() { } // This is the virtual destructor. It must be made virtual, else you get memory leaks - it's not a quick explaination, I recommend you read up on it
    virtual BaseMenu *getNextMenu(int iChoice, bool& iIsQuitOptionSelected) = 0; // This is a 'pure virtual method', as shown by the "= 0". It means it doesn't do anything. It's used to set up the framework
    virtual void printText() // This is made virtual, but doesn't *have* to be redefined. In the current code I have written, it is not redefined as we store the menu text as a string in the object
    {
        std::cout << m_MenuText << std::endl;
    }

protected:
    std::string m_MenuText; // This string will be shared by all children (i.e. derived) classes
};

class FirstMenu : public BaseMenu // We're saying that this FirstMenu class is a type of BaseMenu
{
    FirstMenu()
    {
        m_MenuText = "Main Menu\n"                         // What we are doing here is setting up the string to be displayed later
                    + "Please make your selection\n"       // What we are doing here is setting up the string to be displayed later
                    + "1 - Start game\n"                   // What we are doing here is setting up the string to be displayed later
                    + "2 - Options\n"                      // What we are doing here is setting up the string to be displayed later
                    + "3 - Quit\n"                         // What we are doing here is setting up the string to be displayed later
                    + "Selection: ";                       // What we are doing here is setting up the string to be displayed later
    }

    BaseMenu *getNextMenu(int choice, bool& iIsQuitOptionSelected) // This is us actually defining the pure virtual method above
    {
        BaseMenu *aNewMenu = 0; // We're setting up the pointer here, but makin sure it's null (0)

        switch (choice) // Notice - I have only done "options". You would obviously need to do this for all of your menus
        {
            case 2:
            {
                aNewMenu = new SecondMenu; // We're creating our new menu object here, and will send it back to the main function below
            }

            case 3:
            {
                // Ah, they selected quit! Update the bool we got as input
                iIsQuitOptionSelected = true;
            }

            default:
            {
                // Do nothing - we won't change the menu
            }

        }

        return aNewMenu; // Sending it back to the main function
    }

};

class SecondMenu : public BaseMenu
{
    SecondMenu()
    {
        m_MenuText = "OptionsMenu\n"
                    + "Please make your selection\n"
                    + "1 - ????"
                    + "2 - dafuq?";
    }

    BaseMenu *getNextMenu(int choice, bool& iIsQuitOptionSelected) // This is us actually defining the pure virtual method above
    {
        BaseMenu *aNewMenu = 0; // We're setting up the pointer here, but makin sure it's null (0)

        switch (choice) // Notice - I have only done options. You would obviously need to do this for all of your menus
        {
            case 1:
            {
                aNewMenu = new FirstMenu; // We're creating our new menu object here, and will send it back to the main function below
            }
            break;
            case 2:
            {
                aNewMenu = new FirstMenu; // We're creating our new menu object here, and will send it back to the main function below
            }
            break;

            default:
            {
                // Do nothing - we won't change the menu
            }

        }

        return aNewMenu; // Sending it back to the main function
    }
};

int main (int argc, char **argv)
{
    BaseMenu* aCurrentMenu = new FirstMenu; // We have a pointer to our menu. We're using a pointer so we can change the menu seamlessly.
    bool isQuitOptionSelected = false;
    while (!isQuitOptionSelected) // We're saying that, as long as the quit option wasn't selected, we keep running
    {
        aCurrentMenu.printText(); // This will call the method of whichever MenuObject we're using, and print the text we want to display

        int choice = 0; // Always initialise variables, unless you're 100% sure you don't want to.
        cin >> choice;

        BaseMenu* aNewMenuPointer = aBaseMenu.getNextMenu(choice, isQuitOptionSelected); // This will return a new object, of the type of the new menu we want. Also checks if quit was selected

        if (aNewMenuPointer) // This is why we set the pointer to 0 when we were creating the new menu - if it's 0, we didn't create a new menu, so we will stick with the old one
        {
            delete aCurrentMenu; // We're doing this to clean up the old menu, and not leak memory.
            aCurrentMenu = aNewMenuPointer; // We're updating the 'current menu' with the new menu we just created
        }
    }

    return true;    
}

Note that this might be a bit complex for starting out. I stronglyrecommend you read the other answers people have posted. It should give you a few approaches on how to do it, and you can progress from the basic up to the more complex, examining each change.

请注意,这对于开始来说可能有点复杂。我强烈建议您阅读人们发布的其他答案。它应该为您提供一些关于如何做到这一点的方法,您可以从基本到更复杂,检查每个更改。

回答by John Langan

Looking at what you are trying to do, I would change how you are ensuring the user still want's to play the game first. Look at using a while loop to check if a variable is true or false (people tend to use boolean variables(bool's) for this, an int set to 1 or 0 will do the same). That removes the need for the do-while. Reading up on control logic (if/else, while, for loops) and logical operators (&& - and, || - or, != - not equal to) is recommended. Control logic makes your code do different things, booleans are quick for checking yes/no scenarios and logical operators allow you to check multiple items in one if statement. Some reading: Loops

看看您正在尝试做什么,我会改变您确保用户仍然希望先玩游戏的方式。看看使用 while 循环来检查变量是真还是假(人们倾向于为此使用布尔变量(bool's),设置为 1 或 0 的 int 也会这样做)。这消除了对 do-while 的需要。建议阅读控制逻辑(if/else、while、for 循环)和逻辑运算符(&& - 和、|| - 或、!= - 不等于)。控制逻辑让你的代码做不同的事情,布尔值可以快速检查是/否场景,逻辑运算符允许你在一个 if 语句中检查多个项目。一些阅读:循环

Edit: Have more links for reading material, don't have the rep to post them.

编辑:有更多阅读材料的链接,没有代表发布它们。

Secondly, use another variable (int or whatever suits you) to track what screen you are on. Based on this selection, display different options but still take input 1,2,3 to decide upon the next action.

其次,使用另一个变量(int 或任何适合您的变量)来跟踪您所在的屏幕。根据此选择,显示不同的选项,但仍需输入 1、2、3 来决定下一步操作。

In some terrible pseudo-code here is what I would lean towards:

在一些糟糕的伪代码中,我倾向于:

main()
{
   int choice
   int screen = 1
   bool running = true

   while(running) {
       //Screen 1, Main menu
       if(screen == 1) {
       cout << stuff
       cout << stuff
       cout << option 1
       cout << option 2
       cout << option 3
       cout << selection:
       cin >> choice
       }
       else if(screen == 2){
       //options screen here

       }
       else {
       //default/error message
       }

       //add some choice logic here
       if(screen == 1 && choice == 3){
           //being on screen one AND choice three is quit
           running = false;
       }
       else if(screen == 1 && choice == 2){
           //etc..
       }

  }

}

}

This is my first proper answer, all terrible criticism is well recieved.

这是我的第一个正确答案,所有可怕的批评都得到了好评。