create menus in command line

2019-03-29 10:19发布

问题:

How can one create menus in the command line program? I've tried stuff like:

cin >> input;
switch (input) {
  case (1):
    // do stuff
  case (2):
    // ...
}

but then I've had the problem of sub-menus, and going back to the same menu, etc. The first program I wrote (apart from exercises) that tried to use the switch idea for the menus had goto statements because the alternative was heaps of (at the time) complicated loops.

回答1:

If I tried to count the ways in which one might create a 1,2,3 menu, we'd both be dead before I'd iterated 1/2 of them. But here's one method you could try to get you started (untested, you may need to clean up a couple things):

struct menu_item
{
  virtual ~menu_item() {}
  virtual std::string item_text() const = 0;
  virtual void go() = 0;
};

struct print_hello_item
{
  std::string item_text() const { return "display greeting"; }
  void go() { std::cout << "Hello there, Mr. User."; }
};

struct kill_everyone_item
{
  std::string item_text() const { return "Go on murderous rampage"; }
  void go() { for(;;) kill_the_world(); }
};

struct menu_menu_item
{
  menu_menu_item(std::string const& text) : text_(text), items() {}
  void add_item(std::unique_ptr<menu_item> item) { items.push_back(std::move(item)); }
  void go()
  {
    std::cout << "Choose: \n";
    std::for_each(items.begin(), items.end(), [](std::unique_ptr<menu_item> const& item)
    {
      std::cout << "\t" << item->item_text() << "\n";
    });
    std::cout << "\n\n\tYour choice: ";
    int choice = get_number_from_console();
    if (items.size() > choice) items[choice]->go();
  }
  std::string item_text() const { return text_; }

private:
  std::string text_;
  std::vector<std::unique_ptr<menu_item> > items;
};

int main()
{
  menu_menu_item top_item;
  top_item.add(std::unique_ptr<menu_item>(new print_hello_item));
  top_item.add(std::unique_ptr<menu_item>(new kill_everyone_item));

  top_item.go();
}

As an exercize, how might I define menu items like so:

top_level.add()
  ( "Drive off a cliff", &die_function )
  ( "Destroy the world", &global_thermal_nuclear_war )
  ( "Deeper", submenu()
                ( "Hey, check this shit out!", &gawk ))
;

It can be done with the above framework as a starting point.

This is the difference between OO design and what might be called "procedural". I created an abstraction behind what it means to be a menu choice (which can be another menu) that can be extended in various directions. I create the extensions I need, put them together, and tell the thing to go. Good OO design is just like that...the main part of your program is comprised of putting stuff together and telling it to go.

The key thing to take from this is not necessarily to do it the way I just did, but to think about it in a different way. If you can get the gist of the above code then you'll see that you can add new items, with new menus, to arbitrary depths, without having to deal with the kind of overly complicated code that the switch style causes.



回答2:

You can integrate submenus in your menu with your method:

cin >> input;
switch (input) {
  case (1): 
    cin >> input;
    switch (input) {
       case (1): //do stuff
       case (2): //do stuff
    }
    break;
  case (2):
    break;
}

Is this what you're looking for? Otherwise: What do you want to solve exactly?

Edit: So what you need is an additional loop in your sub-menus with an break condition?

do{
    cin >> input;
    switch (input) {
      case (1): 
        do{
          cin >> input;
          switch (input) {
            case (1): //do stuff
            case (2): //do stuff
          }
        }while(input != 3);
        break;
      case (2):
        break;
    }
  }while(true);


回答3:

I just asked a similar question at Libraries for displaying a text-mode menu? -- it looks like ncurses will dramatically simplify the menu-displaying parts.



标签: c++ menu console