0

我试图在 C 中做一个基本菜单。我应该用 ncurses lib 来做这个。我正在使用本教程: YouTube 上的视频

但是我的版本有一些问题: 1)菜单不能正常打印,只有在选择菜单项时才会显示。然后突出显示不会消失 2)菜单上的选项不会打印在顶部

你能帮助我吗?菜单的想法好还是我应该寻找其他教程(有帮助吗?)。

#include <stdio.h>
#include <ncurses.h>
#include <string.h>
#include <menu.h>
int main(int argc, char **argv)
{
    int i, c;
    char powitanie[]="SLOWNIK UNIWERSALNY";
    int szer, dlug; //wartosci dlugosci i szerokosci terminalu
    initscr(); //Inizjalizacja całości ncurses, kolory itp
    raw();
    noecho();
    keypad(stdscr, TRUE);
    start_color();
    //init_pair(1, COLOR_BLUE, COLOR_BLACK); //wybór kolorów
    getmaxyx(stdscr, szer, dlug); //pobranie rozmiarów terminalu
    move(szer/2, (dlug-strlen(powitanie))/2); //przesuwamy kursor na środek (tak aby się ładnie wydrukowało)
    //attron(COLOR_PAIR(1)); //Aktywujemy wybrane kolory
    printw(powitanie); //Drukujemy powitanie
    //attroff(COLOR_PAIR(1));//Dezaktywujemy kolory
    refresh();//Odswiezamy (inaczej się nie wyswietli)
    WINDOW * menuwin=newwin(6, dlug-12, szer-8, 6); //Definiujemy i tworzymy 'okno'
    box(menuwin, 0, 0);
    refresh();//ponownie odświeżamy aby okno się pojawiło
    wrefresh(menuwin);//odświeżamy samo okno
    keypad(menuwin, TRUE);//umozliwiamy dzialanie klawiatury w oknie
    char *opcje[] = {
                        "Tlumacz z Polskiego na Angielski",
                        "Tlumacz z Angielskiego na Polski",
                        "Edystuj slownik",
                        "Wybierz slownik",
                        "Wyjdz",
                  };
    int wybor;
    int zaznacz=0;
    while(1)//cala ta petla sluzy ciaglemu tworzeniu menu z podswietleniem wybranego elementu
    {
        for(i=0; i<5; i++)
        {
            if(i==zaznacz)
            {
                wattron(menuwin, A_REVERSE);
                mvwprintw(menuwin, i+1, 1, opcje[i]);
                wattroff(menuwin, A_REVERSE);
            }
            wybor = wgetch(menuwin);
            switch(wybor)
            {
                case KEY_UP:
                zaznacz--;
                if(zaznacz==-1) zaznacz=0;//zabezpieczenie przed wyjsciem "poza" menu
                break;
                case KEY_DOWN:
                zaznacz++;
                if(zaznacz==5) zaznacz=4;
                break;
                default:
                break;
            }
            if(wybor==10) break;
        }
        printw("Wybrano:%s", opcje[zaznacz]);
    }
    return(0);
}

PS:代码注释不是英文的,但我希望没有必要

4

1 回答 1

2

这里有很多问题。我已经包含了你的代码的修改版本,我将尝试描述这些变化。

有一些未使用的变量,即argc,argvc,所以我将它们转换void为以消除编译器警告。您可以删除c并更改为int main(void),如果您愿意,可以完全删除这些变量。

我已将stdlib.h头文件添加到您#includeexit()函数中。fail()这在我添加到您的代码中的新错误函数中使用。在用 C 编程时,您应该始终检查您调用的任何函数的返回值。这里特别重要的是首先检查终端是否支持该has_colors()函数的颜色,然后调用start_color()是否成功。如果其中任何一个失败,fail()则调用该函数并显示错误消息,并且程序会以该EXIT_FAILURE值退出。该函数has_colors()返回一个bool,并且该start_color()函数返回一个intOK如果成功,否则ERR)。

现在颜色已经初始化,我看到菜单选择窗口的下边框被菜单文本覆盖。为了解决这个问题,我更改了窗口的大小,使其高出一行:

WINDOW * menuwin=newwin(7, dlug-12, szer-9, 6);

您报告的不正确打印的根本问题是由于for控制菜单项打印的循环中放错了大括号。我借此机会重新组织了循环;现在只有一个电话mvwprintw()A_REVERSE如果当前项也是选中项,则在打印前设置该属性,打印后再次取消设置。

我还将switch语句中的极限测试从等式更改为不等式。例如,在这种情况下使用if (zaznacz < 0)代替是更好的做法。if (zaznacz == -1)我在 final 格式字符串的开头添加了一个换行符printw(),因为某些选择太长而无法放入标题末尾的窗口中。您可以将此输出移动到任何您喜欢的位置。

最后,我在最后一条语句refresh()之后添加了一个,以及一个等待用户在退出程序之前按ENTER 键。在退出 NCurses 程序之前通过调用进行清理非常重要。此功能会在您的程序运行时反转 NCurses 对您的终端所做的更改,如果不这样做可能会导致终端不愉快。printw()getch()endwin()

#include <stdio.h>
#include <ncurses.h>
#include <string.h>
#include <menu.h>
#include <stdlib.h>           // added for exit() function

void fail(char *msg) {
    endwin();
    puts(msg);
    exit(EXIT_FAILURE);
}

int main(int argc, char **argv)
{
    /* Commandline argument currently unused */
    (void) argc;
    (void) argv;

    int i, c;
    (void) c;                       // c is currently unused
    char powitanie[]="SLOWNIK UNIWERSALNY";
    int szer, dlug; //wartosci dlugosci i szerokosci terminalu

    initscr(); //Inizjalizacja całości ncurses, kolory itp
    raw();
    noecho();
    keypad(stdscr, TRUE);

    /* Test to see if terminal has colors */
    if (has_colors() == false) {
        fail("Colors unavailable\n");
    }

    if (start_color() != OK) {
        fail("Unable to start colors\n");
    }

    //init_pair(1, COLOR_BLUE, COLOR_BLACK); //wybór kolorów

    getmaxyx(stdscr, szer, dlug); //pobranie rozmiarów terminalu
    move(szer/2, (dlug-strlen(powitanie))/2); //przesuwamy kursor na środek (tak aby się ładnie wydrukowało)
    //attron(COLOR_PAIR(1)); //Aktywujemy wybrane kolory
    printw(powitanie); //Drukujemy powitanie
    //attroff(COLOR_PAIR(1));//Dezaktywujemy kolory
    refresh();//Odswiezamy (inaczej się nie wyswietli)
    WINDOW * menuwin=newwin(7, dlug-12, szer-9, 6); //Definiujemy i tworzymy 'okno'
    box(menuwin, 0, 0);
    refresh();//ponownie odświeżamy aby okno się pojawiło
    wrefresh(menuwin);//odświeżamy samo okno
    keypad(menuwin, TRUE);//umozliwiamy dzialanie klawiatury w oknie

    char *opcje[] = {
        "Tlumacz z Polskiego na Angielski",
        "Tlumacz z Angielskiego na Polski",
        "Edystuj slownik",
        "Wybierz slownik",
        "Wyjdz",
    };
    int wybor;
    int zaznacz=0;

    while(1)//cala ta petla sluzy ciaglemu tworzeniu menu z podswietleniem wybranego elementu
    {
        for(i = 0; i < 5; i++) {
            if(i == zaznacz)
                wattron(menuwin, A_REVERSE);
            mvwprintw(menuwin, i+1, 1, opcje[i]);
            if (i == zaznacz)
                wattroff(menuwin, A_REVERSE);
        }

        wybor = wgetch(menuwin);
        switch(wybor)
        {
        case KEY_UP:
            zaznacz--;
            if(zaznacz < 0) zaznacz = 0;//zabezpieczenie przed wyjsciem "poza" menu
            break;
        case KEY_DOWN:
            zaznacz++;
            if(zaznacz > 4) zaznacz = 4;
            break;
        default:
            break;
        }

        if(wybor==10) break;
    }

    printw("\nWybrano:%s", opcje[zaznacz]);
    refresh();

    /* Wait for user to press enter to exit */
    getch();

    /* Need to cleanup before exit */
    endwin();

    return 0;
}
于 2017-01-13T03:48:30.353 回答