-5

学期の最後のプロジェクトに向けてコーディングを行っていますが、コードの重複の問題があります。ncursesまたはを使用pdcursesして、ユーザーとやり取りするメニューを作成しています。

問題: メニューの選択肢 (合計 5 つ) ごとに、サブメニューが必要です。メイン メニューとのサブメニューの唯一の違いは、出力される配列と、配列サイズItemsの結果として、いくつかの関数に入るパラメーターです。Items5 つのサブメニューが必要なので、同じコードが 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);
}

ありがとうございました。

psコードは本からのものです。ncurses の経験がほとんどない

4

1 に答える 1

2

シンプルなメニュー方式のプログラム。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オプションのリストとオプションの実行命令によって駆動されます。別のオプションが必要ですか?リストにアイテムを追加し、そのオプションの義務を果たすための新しい機能を提供する可能性があります。

空欄を埋めるだけです。

于 2016-06-02T00:19:13.937 に答える