2011-01-14 9 views
5

Wie kann man Menüs im Befehlszeilenprogramm erstellen? Ich habe versucht, Sachen wie:Menüs in der Befehlszeile erstellen

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

aber dann habe ich das Problem des Untermenü habe, und gehe zurück auf das gleiche Menü, etc. Das erste Programm, das ich (abgesehen von Übungen) schrieb, die versucht, Verwenden Sie die switch Idee für die Menüs hatte goto Aussagen, weil die Alternative war Haufen von (zu der Zeit) komplizierte Schleifen.

Antwort

8

Wenn ich versuchte zu zählen, wie man ein 1,2,3-Menü erstellen könnte, wären wir beide tot, bevor ich 1/2 von ihnen wiederholt hätte. Aber hier ist eine Methode, die Sie könnten versuchen Sie, um loszulegen (ungetestet, müssen Sie möglicherweise ein paar Dinge aufzuräumen):

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(); 
} 

Als exercize, wie könnte ich Menüpunkte wie so definieren:

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

Es kann mit dem obigen Rahmen als Ausgangspunkt getan werden.

Dies ist der Unterschied zwischen OO-Design und was "prozedural" genannt werden könnte. Ich habe eine Abstraktion hinter dem, was es bedeutet, eine Menüwahl zu sein (die ein anderes Menü sein kann), die in verschiedene Richtungen erweitert werden kann, erstellt. Ich erstelle die Erweiterungen, die ich brauche, lege sie zusammen und sage dem Ding, dass es gehen soll. Gutes OO-Design ist einfach so ... Der Hauptteil deines Programms besteht darin, Dinge zusammenzusetzen und zu sagen, dass es gehen soll.

Der Schlüssel dazu ist nicht notwendigerweise, es so zu machen, wie ich es gerade getan habe, sondern darüber anders zu denken. Wenn Sie den Kern des obigen Codes finden können, werden Sie sehen, dass Sie neue Elemente mit neuen Menüs zu beliebigen Tiefen hinzufügen können, ohne sich mit der Art des übermäßig komplizierten Codes, den der Schalterstil verursacht, auseinanderzusetzen.

+0

Ich gehe davon aus, dass dies eine bevorzugte Lösung ist, da es flexibler ist, und Sie könnten das Framework-y Zeug in einer anderen Datei speichern und später darauf verweisen. –

+0

Es ist sicherlich zu jedem Wechselweg vorzuziehen. Ja, Sie könnten es sicherlich mit einer Art von Dateiformat-Leser erweitern, so dass das Menü auch von externen Eingaben erstellt wurde. –

+0

std :: struct in kill_everyone_item sollte durch std :: string ersetzt werden – Septagram

2

Sie können Untermenüs in Ihrem Menü mit Ihrer Methode integrieren:

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

Ist das, was Sie suchen? Ansonsten: Was willst du genau lösen?

Edit: Also, was Sie brauchen, ist eine zusätzliche Schleife in Ihren Untermenüs mit einer Break-Bedingung?

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); 
+0

Im Kontext des Menüs, das Sie geben, hatte ich gehofft, dass, sobald der Benutzer eine Aktion abgeschlossen hat (wie die ersten Schritte), es zurück zum Untermenü gehen würde, und dass es eine Option geben würde erste Menü, macht das Sinn? –

+0

Ah, okay - ich sehe ... Ich habe Quellcode für diesen Fall hinzugefügt – Constantin

+0

Das scheint wie es funktionieren würde –

1

Ich habe gerade eine ähnliche Frage an Libraries for displaying a text-mode menu? gestellt - es sieht aus wie Ncurses wird drastisch vereinfachen die Menü-Anzeige von Teilen.

+1

imho, ncurses ist keine gute Antwort, da seine Menüs nicht OOP sind und stattdessen '*' und '**' zeigerbasierte verknüpfte Listen implementieren. Ich bin auf einer ähnlichen Suche nach einem Menü, nav, Steuerklasse/Bibliothek und versuche, YAIEI oder YAPBLL nicht zu tun. Noch eine andere (if-else-if | pointer-basierte verknüpfte Liste) –

+0

Ich stimme zu. Ich habe versucht, die Curses-Menüfunktionalität zu verwenden, gab aber auf und schrieb stattdessen meine eigene (C++ - style, STL-using) Version. Ich füge das zu der Frage hinzu, die ich gestellt habe. – ExOttoyuhr

+0

Ich gab auf OOP auf. :(Ich fühle mich irgendwie wie ein Versager, aber ich muss wieder arbeiten, und dieses einwöchige Unterfangen, OOP zu versuchen, war genug. Ich kann einfach nicht die Stücke in meinem Gehirn zusammenziehen. Ich nahm dieses Musterbeispiel von 1995 und es tut, was ich will http://dec.bournemouth.ac.uk/staff/awatson/micro/articles/9509_066.pdf Probe ist in meinem Github. –