2016-06-01 8 views
-5

私は学期の最後のプロジェクトに向かう途中でコードを作成しており、コードの重複問題があります。 ncursesまたはpdcursesを使用して、ユーザーと対話するメニューを作成しています。同一のサブメニューのC++コードの削減

問題:メニューの各選択肢(合計5個)にはサブメニューが必要です。メインメニューとのサブメニューの唯一の違いは、Itemsの配列サイズの結果として、Itemsの配列が印刷され、いくつかの関数に入るパラメータです。 5つのサブメニューが必要なので、同じコードの5倍(メインメニューを追加する場合は6つ)が必要です。

同じことをする関数を作成するのに手伝ってもらえますか?メニューを作成するのに6回呼び出しますか?

ここに私のコードだ

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の機能とスタンダードライブラリの視界から隠されたスマーフなコードに縮小され、あなたや私よりもこのようなものを手に入れる経験がはるかに多い人によって書かれています。可能な限り、巨人の

domenuは、オプションのリストとオプションの実行手順によって駆動されます。別のオプションが必要ですか?アイテムをリストに追加し、おそらくそのオプションの義務を果たすための新しい機能を提供する。

あなたがしなければならないのは、空白を記入することだけです。

+0

これは良い方法だと思われますが... ncursesを使用する必要があるので、それを受け入れることはできません。/ –

+0

これはメニューシステムを提供するだけです。すべてのcin-coutは目的のためのもので、フロントエンドとして必要なものに簡単に置き換えられます - curses、ncurses、GUI、殺人的なCare Bearsの軍隊.... – user4581301

関連する問題