Основное меню Ncurses

Я пытаюсь сделать базовое меню на 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: комментарии к коду не на английском языке, но я надеюсь, что они не понадобятся


person Jacek    schedule 13.01.2017    source источник


Ответы (1)


Здесь довольно много проблем. Я включил модифицированную версию вашего кода, которая работает, и я попытаюсь описать изменения.

Были некоторые неиспользуемые переменные, а именно argc, argv и c, поэтому я привел их к void, чтобы отключить предупреждения компилятора. Вы можете удалить c и изменить на int main(void), если хотите, полностью удалив эти переменные.

Я добавил заголовочный файл stdlib.h в ваши #include для функции exit(). Это используется в новой функции ошибок fail(), которую я добавил в ваш код. Вы должны всегда проверять возвращаемые значения любой функции, которую вы вызываете при программировании на C. Здесь особенно важно сначала проверить, поддерживает ли терминал цвет с помощью функции has_colors(), а затем успешно ли выполнен вызов start_color(). Если какой-либо из них терпит неудачу, функция fail() вызывается с сообщением об ошибке, и программа завершается со значением EXIT_FAILURE. Функция has_colors() возвращает bool, а функция start_color() возвращает int (OK в случае успеха, иначе ERR).

Теперь, когда цвета были инициализированы, я вижу, что нижняя граница вашего окна выбора меню перезаписывается текстом меню. Чтобы исправить это, я изменил размер вашего окна, сделав его на одну строку выше:

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

Фундаментальная проблема неправильной печати, о которой вы сообщили, связана с неуместной фигурной скобкой в ​​цикле for, управляющем печатью пунктов меню. Я воспользовался возможностью, чтобы немного реорганизовать цикл; теперь есть только один вызов mvwprintw(). Атрибут A_REVERSE устанавливается перед печатью, если текущий элемент также является выбранным элементом, и снова сбрасывается после печати.

Я также изменил предельные тесты в операторе switch с равенства на неравенство. В таких случаях лучше использовать, например, if (zaznacz < 0) вместо if (zaznacz == -1). Я добавил символ новой строки в начало строки формата в финальном printw(), так как некоторые из вариантов слишком длинные, чтобы поместиться в окне в конце заголовка. Вы можете переместить этот вывод куда угодно.

Наконец, я добавил refresh() после последнего оператора printw() и getch(), чтобы дождаться нажатия пользователем ENTER перед выходом из программы. Очень важно выполнить очистку, вызвав endwin() перед выходом из программы NCurses. Эта функция отменяет изменения, внесенные NCurses в ваш терминал во время работы вашей программы, и невыполнение этого может привести к неприятным последствиям для терминала.

#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;
}
person ad absurdum    schedule 13.01.2017
comment
Заголовок menu.h в примере не используется. - person Thomas Dickey; 13.01.2017