2016-06-01 2 views
-5

Я кодирую свой путь к последнему проекту семестра, и у меня проблема с дублированием кода. Я использую ncurses или pdcurses, чтобы создать меню для взаимодействия с пользователем.Сокращение кода на C++ для идентичных подменю

Проблема: для каждого выбора меню (всего пять) мне нужно подменю. Единственное отличие подменю от главного меню - массив Items для печати и параметры, которые входят в некоторые функции, в результате размера массива Items. Поскольку мне нужно пять подменю, мне нужно пять раз один и тот же код (шесть, если вы добавите главное меню).

Может ли кто-нибудь из вас помочь мне сделать функцию, которая делает то же самое, что я тогда позвоню шесть раз, чтобы создать мое меню?

Вот мой код

void Menu(){ 
    const char* Items[]={ 
     "[1]...New tax declaration", 
     "[2]...Modify tax declaration", 
     "[3]...Cancel tax declaration", 
     "[4]...Additional Information", 
     "[5]...Exit" 
    }; 
    int Cur=0; 
    int ch, i; 
    int flag=0; 
    do{ 
     werase(wm); 
     mvwaddstr(wm, 2, 16, "MENU"); 
     for(int i=0; i<5;i++){ 
      if(i==Cur) 
       wattr_on(wm, A_REVERSE, 0); 
      mvwaddstr(wm, 4+i, 4, Items[i]); 
      wattr_off(wm, A_REVERSE, 0); 
     } 
     mvwaddstr(wm, 14, 3, "Choice: "); 
     wprintw(wm, "%1d", Cur+1); 
     wrefresh(wm); 
     ch=wgetch(wm); 
     switch(ch){ 
      case '1':Cur=0;Sub2();break; 
      case '2':Cur=1;Sub1();break; 
      case '3':Cur=2;break; 
      case '4':Cur=3;break; 
      case '5':flag=1;break; 
      case KEY_UP: 
      case KEY_LEFT: Cur--; if (Cur<0) Cur=4; break; 
      case KEY_DOWN: 
      case KEY_RIGHT: Cur++; if(Cur>4) Cur=0; break; 
      case 27: flag=1; break; 
      case 32: 
      case 13: 
       switch (Cur){ 
        case 0:Sub2();break; 
        case 1:Sub1();break; 
        case 2:break; 
        case 3:break; 
        case 4:flag=1;break; 
       } 
     } 
    }while(!flag); 
} 

Спасибо.

p.s Код из книги. У меня мало опыта работы с ncurses, так что не слишком сильно на меня: P. Я просто хочу, чтобы мой последний код проекта был лучше :).

+0

это может вас заинтересовать - http://meta.stackexchange.com/questions/10811/how-do-i-ask-and-answer-homework-questions –

+0

Это было действительно полезно. –

ответ

1

Простая программа, управляемая меню. Это основано на использовании std::map вместо условной логики. На этой карте хранится список структур menuitem, которые определяют, как выглядит меню и что делает каждый из них.

Это лучше всего объяснить, поскольку мы работаем с кодом, поэтому давайте погрузимся!

// headers for everything used in this example 
#include <iostream> 
#include <string> 
#include <map> 
#include <functional> 
#include <cctype> 

// function to perform menu option B sub option 1 
void optionB1() 
{ 
    std::cout << "perfoming B1" << std::endl; 
} 

// function to perform menu option B sub option 2 
void optionB2() 
{ 
    std::cout << "perfoming B2" << std::endl; 
} 

// function to perform menu option A 
void optionA() 
{ 
    std::cout << "perfoming A" << std::endl; 
} 

// defines a menu item. Good naming can often save the need to comment 
struct menuitem 
{ 
    std::function<void()> doIt; // function to run if option chosen 
    std::string description; // pretty message describing option 
}; 

// draw menu and wait for the user to select an option. 
void domenu(const std::map<char, menuitem> & menu) 
{ 
    while (true) // loop until user gives a good option. Or use a retry count. 
       // You decide. 
    { 
     for (auto &items : menu) 
     { // for all items in the menu, print out the item and it's description text 
      // for what first and second mean, read up on std::map and std::pair 
      std::cout << items.first << ") " << items.second.description << std::endl; 
     } 
     char ch; 
     std::cin >> ch; // get the user's choice 
     // often you may want to eliminate one of the cases to reduce the amount 
     // of possible inputs you need to provide handling code for. 
     // the line below allows us to use the same code for input of A and a. 
     ch = std::tolower(ch); // convert input to lower case 
     try 
     { 
      menu.at(ch).doIt(); // call the function mapped to user's choice. 
           // this may do produce something or it may 
           // display another menu. It could end the wor-- 
      return; // done. 
     } 
     catch (...) 
     { // print error message on unsupported input 
      std::cout << "Error. Invalid option!" << std::endl; 
     } 
    } 
} 


// the B menu 
std::map<char, menuitem> bmenu 
{ // User input doIt function  Description 
    {'1',  {optionB1,   "Option B1"}}, 
    {'2',  {optionB2,   "Option B2"}} 
    // add more options here. Or don't. Up to you. 
}; 

// the main menu 
std::map<char, menuitem> mainmenu 
{ // User input doIt function    Description 
    {'a',  {optionA,     "Option A"}}, 
    {'b',  {std::bind(domenu, bmenu), "Option B"}} 
    // OK, so that last one was a bit weird. std::bind makes a function and 
    // specifies the arguments with which it will be called. This takes 
    // domenu binds it with bmenu so that std::function<void()> is 
    // satisfied. As far as the world is concerned, the bound function 
    // returns nothing and takes no parameters. Very complicated functions 
    // can be bound so long as the end result returns nothing and requires 
    // no parameters. 
    // what it's doing here is allowing us to call domenu to draw the B 
    // submenu, wait for valid input, and call the chosen function. 
}; 

// good 'ol trusty main so we can test that the above code isn't utter BS. 
int main() 
{ 
    while (true) // loop forever. Or use whatever exit logic is required. 
    { 
     domenu(mainmenu); // kick-start by calling do menu to run the main menu 
    } 
    return(0); 
} 

Это позволит свести код к минимуму. Весь дублированный код сводится к функции domenu и smurfload кода, скрытого от зрения в стандартной библиотеке и написанного людьми, которые, вероятно, имеют гораздо больше опыта в получении этого материала, чем вы или я. По возможности, встаньте на плечи гигантов.

domenu управляется списками опций и инструкциями по выполнению этой опции. Хотите другой вариант? Добавьте элемент в список и, возможно, предоставите новую функцию для выполнения обязательств по этому варианту.

Все, что вам нужно сделать, это заполнить пробелы.

+0

Это похоже на хороший способ сделать это, но ... Мне нужно использовать ncurses, поэтому, даже если я сделаю это, это не будет принято:/ –

+0

Это просто предоставляет систему меню. Все cin-cout являются, например, целями и легко заменяются тем, что вы хотите, как передним концом - проклятиями, ncurses, графическим интерфейсом, армией убийственных Care Bears .... – user4581301

Смежные вопросы