首页 > 解决方案 > C ++,ncurses:在按下键之前无法显示菜单

问题描述

我和一个朋友正在终端内开发类似俄罗斯方块的游戏。我们使用 ncurses 来管理它,我们有不同的“观点”。例如,一个视图管理网格,而另一个视图管理菜单。但是我们有一个问题:当我们开始游戏时,我们需要按一个键才能看到它,否则窗口是空的。

这是我们创建菜单(构造函数)时运行的代码:

MenuScreen::MenuScreen()
{
    if (has_colors())
    {
        use_default_colors();
        start_color();
        init_pair(WHITEONRED, COLOR_WHITE, COLOR_RED);
        init_pair(WHITEONBLUE, COLOR_WHITE, COLOR_BLUE);
        init_pair(REDONWHITE, COLOR_RED, COLOR_WHITE);
    }

    char *choices[] = /* The menu choices */
        {
            (char *)"            Solo              ",
            (char *)"            Bot               ",
            (char *)"            Tetrix            ",
            (char *)"            Quitter           ",
            NULL};

    /* Calculate nchoices */
    for (n_choices = 0; choices[n_choices]; n_choices++)
        ;

    /* alloction of an iteam array for the menu */
    my_items = (ITEM **)calloc(n_choices + 1, sizeof(ITEM *));
    for (ssChoice = 0; ssChoice < n_choices; ++ssChoice)
        my_items[ssChoice] = new_item(choices[ssChoice], NULL);

    my_items[n_choices] = (ITEM *)NULL;

    /* menu structure creation */
    my_menu = new_menu((ITEM **)my_items);

    /* symbole  on the left of selected iteam*/
    set_menu_mark(my_menu, "> ");

    /* Windows Border cration */
    wBorder = newwin(8, 40, LINES / 2 - 8 / 2, COLS / 2 - 40 / 2);
    registerWindow(wBorder);
    wattrset(wBorder, COLOR_PAIR(WHITEONRED));
    windowsFilling(wBorder);
    box(wBorder, 0, 0);
    windowsBorderTitle(wBorder, " option ");

    wUI = derwin(wBorder, 8 - 2, 40 - 2, 2, 2);
    registerWindow(wUI);

    set_menu_sub(my_menu, wUI);

    set_menu_fore(my_menu, COLOR_PAIR(REDONWHITE));
    set_menu_back(my_menu, COLOR_PAIR(WHITEONRED));

    /* menu display */
    post_menu(my_menu);
}

当按下下一个键时:

void MenuScreen::next()
{
    menu_driver(my_menu, REQ_DOWN_ITEM);
    update();
}

这是 update() 包含的内容:

void MenuScreen::update()
{
    touchwin(wUI);
    wrefresh(wUI);
    touchwin(wBorder);
    wrefresh(wBorder);
}

如果我们update()next()函数中删除,当我们按下下一个键时菜单不再显示,所以我们尝试update()在构造函数的末尾添加一个调用,但这不起作用。我们不知道是什么导致了这个错误。这是我们的完整源代码: https ://github.com/Th0rgal/poyuterm/tree/22e2422930a29fbe83414e382fd566c3eac69366

编辑:这是我朋友制作的最小可重复示例:

要构建它,请将其复制粘贴到 menu.cpp 文件中并键入:g++ menu.cpp -o menu -lncurses -l menu

#include <stdlib.h> /* calloc() */
#include <string.h> /* strlen() */
#include <ncurses.h>
#include <menu.h>
#include <curses.h>

#define WHITEONRED 10
#define WHITEONBLUE 20
#define WHITEONBLACK 30
#define BLACKONWHITE 40
#define REDONWHITE 50

void windowsBorderTitle(WINDOW *pwin, const char *title)
{
    int x, maxy, maxx, stringsize;
    getmaxyx(pwin, maxy, maxx);
    stringsize = 4 + strlen(title);
    x = (maxx - stringsize) / 2;
    mvwaddch(pwin, 0, x, ACS_RTEE);
    waddch(pwin, ' ');
    waddstr(pwin, title);
    waddch(pwin, ' ');
    waddch(pwin, ACS_LTEE);
}

void windowsFilling(WINDOW *pwin)
{
    int y, x, maxy, maxx;
    getmaxyx(pwin, maxy, maxx);
    for (y = 0; y < maxy; y++)
        for (x = 0; x < maxx; x++)
            mvwaddch(pwin, y, x, ' ');
}

int main(int argc, char const *argv[])
{
    initscr();      /* start ncurses */
        cbreak();       /* immediately acquire each keystroke */
        noecho();       /* do not echo user keystrokes */
    keypad(stdscr, TRUE);   /* enable detection of function keys */


    int c;
    ITEM **my_items;
    MENU *my_menu;

    WINDOW *wUI;
    WINDOW *wBorder;

    int n_choices;
    int ssChoice;
    int my_choice = -1;
    if (has_colors())
    {
        use_default_colors();
        start_color();
        init_pair(WHITEONRED, COLOR_WHITE, COLOR_RED);
        init_pair(WHITEONBLUE, COLOR_WHITE, COLOR_BLUE);
        init_pair(REDONWHITE, COLOR_RED, COLOR_WHITE);
    }

    char *choices[] = /* The menu choices */
        {
            (char *)"            Solo              ",
            (char *)"            Bot               ",
            (char *)"            Tetrix            ",
            (char *)"            Quitter           ",
            NULL};

    for(n_choices=0; choices[n_choices]; n_choices++);

    /* ALLOCATE ITEM ARRAY AND INDIVIDUAL ITEMS */
        my_items = (ITEM **)calloc(n_choices + 1, sizeof(ITEM *));
        for(ssChoice = 0; ssChoice < n_choices; ++ssChoice)
                my_items[ssChoice] = new_item(choices[ssChoice], NULL);
    my_items[n_choices] = (ITEM *)NULL;

    /* CREATE THE MENU STRUCTURE */
    my_menu = new_menu((ITEM **)my_items);

    /* PUT > TO THE LEFT OF HIGHLIGHTED ITEM */
    set_menu_mark(my_menu, "> ");

    /* SET UP WINDOW FOR MENU'S BORDER */
    wBorder = newwin(16, 40, 2, 20);
    wattrset(wBorder, COLOR_PAIR(WHITEONRED) | WA_BOLD);
    windowsFilling(wBorder); 
    box(wBorder, 0, 0);
    windowsBorderTitle(wBorder, "Choose one");

    /* SET UP WINDOW FOR THE MENU'S USER INTERFACE */
    wUI = derwin(wBorder, 16-2, 40-2, 2, 2);

    /* ASSOCIATE THESE WINDOWS WITH THE MENU */
    set_menu_win(my_menu, wBorder);
    set_menu_sub(my_menu, wUI);

    /* MATCH MENU'S COLORS TO THAT OF ITS WINDOWS */
    set_menu_fore(my_menu, COLOR_PAIR(REDONWHITE));
    set_menu_back(my_menu, COLOR_PAIR(WHITEONRED) | WA_BOLD);

    /* SET UP AN ENVIRONMENT CONDUCIVE TO MENUING */
    keypad(wUI, TRUE);  /* enable detection of function keys */
    noecho();       /* user keystrokes don't echo */
    curs_set(0);        /* make cursor invisible */

    /* DISPLAY THE MENU */
    post_menu(my_menu);

    touchwin(wBorder);
    wrefresh(wBorder);  

    while(my_choice == -1)
    {
        touchwin(wBorder);
        wrefresh(wBorder);
        touchwin(wUI);  /* refresh prior to getch() */
        wrefresh(wUI);  /* refresh prior to getch() */
        c = getch();
        switch(c)
        {
        case KEY_DOWN:
            menu_driver(my_menu, REQ_DOWN_ITEM);
            break;
        case KEY_UP:
            menu_driver(my_menu, REQ_UP_ITEM);
            break;
        case 10:    /* Enter */
            my_choice = item_index(current_item(my_menu));

            pos_menu_cursor(my_menu);
            break;
        }
    }
    unpost_menu(my_menu);
    for(ssChoice = 0; ssChoice < n_choices; ++ssChoice)
        free_item(my_items[ssChoice]);
    free_menu(my_menu);

    delwin(wUI);
    delwin(wBorder);

    touchwin(stdscr);
    wrefresh(stdscr);

    endwin();
}

标签: c++ncurses

解决方案


推荐阅读