mvwprintw действует неожиданно в течение цикла - PullRequest
1 голос
/ 03 октября 2019

В настоящее время я пишу функцию, которая создает окно меню с текстом, расположенным по-разному в зависимости от параметров. При горизонтальной печати содержимого массива первый вызов menu () работает должным образом (слова печатаются горизонтально с пробелами между ними). ​​Однако если функция вызывается снова, позиция x printf не изменится, что приведет к перезаписи mvwprintwпредыдущее слово. Это может указывать на то, что что-то не так с моим циклом for, по крайней мере, для меня, однако создание вертикальных меню работает, как и ожидалось, с каждым словом, напечатанным под последним.

nmenu.c

#include "nmenu.h"
#include <ncurses.h>
#include <stdlib.h>
#include <string.h>

int menu(char title[], char description[], char *choices[], int choicesSize, bool vertical, bool centered)
{
    int menuXMax = 0;
    int highlight = 0;
    int menuHeight = 9;
    int menuWidth = 30;
    int choicesLength = 0;
    int yMax, xMax;

    getmaxyx(stdscr, yMax, xMax);

    for(int i; i < choicesSize; i++)
    {
        if(strlen(choices[i]) > choicesLength)
        {
            choicesLength = strlen(choices[i]);
        }
    }

    if(vertical)
    {
        menuHeight = choicesSize+8;
        menuWidth = choicesLength+4;
    } else
    {
        menuWidth = choicesLength*choicesSize+choicesSize;
    }

    if(strlen(description) > menuWidth)
    {
        menuWidth = strlen(description)+4;
    }

    WINDOW *menu = newwin(menuHeight, menuWidth, yMax/2-menuHeight/2, xMax/2-menuWidth/2);
    box(menu, 0, 0);
    refresh();
    wrefresh(menu);
    keypad(menu, true);

    wattron(menu, A_REVERSE);
    mvwprintw(menu, 0, 2, title);
    wattroff(menu, A_REVERSE);

    mvwprintw(menu, 2, menuWidth/2-strlen(description)/2, description);
    mvwprintw(menu, menuHeight-3, menuWidth/2-4, "[C]ancel");

    menuXMax = getmaxx(menu);

    while(true)
    {
        for(int i = 0; i < choicesSize; i++)
        {
            if(i == highlight)
            {
                wattron(menu, A_REVERSE);
            }

            if(vertical)
            {
                if(centered)
                {
                    mvwprintw(menu, i+4, menuXMax/2-strlen(choices[i])/2, choices[i]);
                } else
                {
                    mvwprintw(menu, i+4, 2, choices[i]);
                }
            } else
            {
                if(centered)
                {
                    mvwprintw(menu, 4, (menuXMax/2-choicesLength*choicesSize/2)+choicesLength*i, choices[i]);
                } else
                {
                    mvwprintw(menu, 4, 2+choicesLength*i, choices[i]);
                }
            }

            wattroff(menu, A_REVERSE);
        }

        switch(wgetch(menu))
        {
            ... // User input 
        }
    }

    MenuBreak: ;

    return 0;
}

test.c

#include "nmenu.h"
#include <ncurses.h>

char *choices[4] = {"Yes", "No", "Maybe", "Sometimes"};

int main()
{
    // Start ncurses
    initscr();
    noecho();
    cbreak();
    curs_set(0);

    menu("Ver 1", "Choices should be uncentered and presented vertically", choices, 4, true, false);
    menu("Ver 2", "Choices should be centered and presented vertically", choices, 4, true, true);

    // End ncurses
    getch();
    endwin();

    return 0;
}

test.c выведет первое меню в обычном режиме, причем второе меню имеет перекрывающийся текст. Это также происходит, когда порядок вызовов переключается. Я просто не могу понять, почему цикл for не будет повторяться должным образом при повторном запуске функции.

1 Ответ

0 голосов
/ 03 октября 2019

В следующей строке:

for(int i; i < choicesSize; i++)

переменная i не инициализирована. Он должен быть установлен в ноль, чтобы он выглядел следующим образом:

for(int i = 0; i < choicesSize; i++)

Тогда choicesLength будет правильно рассчитан, и горизонтальное расположение также будет работать.

Демо

Снимок экрана с результатом выглядит следующим образом:

screenshot

Неопределенное поведение

Переменныекоторые не инициализируются, приводят к неопределенному поведению в C и, следовательно, их следует избегать во всяком случае.

Полезно включить предупреждения компилятора, например, при использовании

gcc -Wextra -Wall main.c nmenu.c -o tst -lncurses

отображается это полезное сообщение:

nmenu.c:16:16: warning: variable 'i' is uninitialized when used here [-Wuninitialized]
for(int i; i < choicesSize; i++)
           ^
...