wprintw: в ncurses при написании строки, заканчивающейся новой строкой, той же ширины, что и окно, печатаются две новые строки.

Я только что закончил работать с кодом программы CLI, преобразовав его в программу TUI с помощью ncurses.

Он проверяет пользователя по набору вопросов и ответов в виде флеш-карты.

Все прошло относительно гладко, за исключением того, что я заменил многие вызовы printf() функцией popupinfo(int colour,char * title, char * body) для всплывающего окна.
Эта функция использует следующие функции:

int textwidth (char * text);//returns the width of a given string (which may include newlines) in chars when displayed without wrapping (for purposes of determining optimum window width)
int textheight (char * text, int width);//returns the height of a given string (which may include newlines) in lines when displayed wrapped to the given width (for purposes of determining optimum window width)

чтобы вычислить размер окна, прежде чем использовать wprintw() для печати в этом окне.

Моя проблема заключается в том, что когда длина строки, отличной от последней строки, точно равна ширине окна (или кратна ширине окна), одна или несколько строк текста будут исключены из окна.

Например:

Answer:

Foobarbaz.

будет печатать правильно, но в:

Answer:

Foo.

«Фу». не печатается.

Я полагаю, это связано с тем, что функция wprintw() перемещает курсор на новую строку после печати (window_width) символов, но затем встречает символ новой строки, который был в конце только что напечатанной строки.

Кто-нибудь знает способ (за исключением написания целой функции для обработки вывода самостоятельно), чтобы остановить это?

Полезные детали:

Я заменяю:

printf("\nSorry, the correct answer is:\n\n\t%s\n\n",currententry->answer);

с участием:

sprintf(passingstring,"The correct answer is:\n\n%s",currententry->answer);
popupinfo(3,"Sorry!",passingstring);

всплывающая информация определяется как:

void popupinfo(int colour,char * title,char * message)//pops up a window with the given colour, title and text
{
    WINDOW * wbpopup = NULL, * wpopup = NULL;
    PANEL * ppopup = NULL;
    int width, height;

    width=textwidth(message);
    getmaxyx(stdscr,nlines,ncols);
    if (width>ncols-16)width=ncols-16;
    height=textheight(message,width)+4;
    width+=8;
    if (!(wbpopup = newwin(height,width,(nlines-height)/2,(ncols-width)/2))) outofmemory();
    ppopup = new_panel(wbpopup);
    wattrset(wbpopup,COLOR_PAIR(colour));
    werase(wbpopup);
    wbkgd(wbpopup,COLOR_PAIR(colour));
    box(wbpopup,0,0);
    windowtitle(wbpopup,title);
    wpopup = innerwindow(wbpopup);

    wprintw(wpopup,message);
    update_panels();
    doupdate();
    wgetch(wpopup);

    delwin(wpopup);
    del_panel(ppopup);
    delwin(wbpopup);
    update_panels();
    doupdate();
}

Также полезно:

int textwidth (char * text)//returns the width of a given string (which may include newlines) in chars when displayed without wrapping (for purposes of determining optimum window width)
{
    int i=0,j=0,k=0;
    while (text[i]!='\0')
    {
        if (text[i]=='\n')
        {
            k=j>k?j:k;
            j=0;
        }
        else j++;
        i++;
    }
    k=j>k?j:k;
    return k;
}

а также

int textheight (char * text, int width)//returns the height of a given string (which may include newlines) in lines when displayed wrapped to the given width (for purposes of determining optimum window width)
{
    int i=0,j=0,k=1;
    while (text[i]!='\0')
    {
        if (text[i]=='\n')
        {
            k++;
            j=0;
        }
        else j++;
        if (j>width)
        {
            k++;
            j=1;
        }
        i++;
    }
    return k;
}

Другие функции:

WINDOW * innerwindow(WINDOW * outerwindow);//creates an area within another window for purposes of displaying text with a margin
void windowtitle(WINDOW * window, char * title);//writes the given string to the given window (top centre)

Для получения дополнительной информации см. полный исходный код версий CLI и ncurses, который можно найти по адресу http://github.com/megamasha


person M_M    schedule 24.09.2011    source источник
comment
Я подозреваю, что ваша проблема не имеет ничего общего со sprintf (поскольку в нем нет ошибки и он действительно работает). Я подозреваю, что это связано с вашим кодом ncurses и вашими окнами. Вы можете отредактировать заголовок вопроса, чтобы отразить это.   -  person Brian Roach    schedule 24.09.2011
comment
Я присоединюсь к комментарию Брайана Роуча о том, что этот вопрос неправильно назван. Вы можете убедиться, что sprintf работает, записав его в журнал или консоль. Или передать фиксированную строку, например: Это должно отображаться на экране вместо вывода sprintf.   -  person P.T.    schedule 24.09.2011
comment
Я буду четвертым :) ... и поднимите уровень предупреждения вашего компилятора; и обратите внимание на предупреждения.   -  person pmg    schedule 24.09.2011
comment
Хорошо, я дважды проверю, действительно ли вывод sprintf включает строку, а затем соответствующим образом переименую вопрос.   -  person M_M    schedule 24.09.2011
comment
Строка кажется в такт при отправке ее в stderr, но последняя строка не отображается на экране. Я думаю, это связано с тем, что char * содержится в последней строке и, возможно, выталкивается из нижней части окна (из-за новых строк, появляющихся откуда-то непредвиденно). К сожалению, сейчас мне нужно идти и настраивать пианино, так что дальнейшее расследование придется отложить до завтра или, возможно, даже до понедельника.   -  person M_M    schedule 24.09.2011
comment
В принципе, вы должны использовать snprintf и strncpy вместо sprintf и strcpy, чтобы избежать переполнения.   -  person Craig    schedule 29.09.2011


Ответы (1)


Вы абсолютно правы, когда говорите:

Я полагаю, это связано с тем, что функция wprintw() перемещает курсор на новую строку после печати (window_width) символов, но затем встречает символ новой строки, который был в конце только что напечатанной строки.

Что касается вашего вопроса

Кто-нибудь знает способ (за исключением написания целой функции для обработки вывода самостоятельно), чтобы остановить это?

- такого способа нет, потому что вы наблюдаете, как работает перенос строк в ncurses. Что вы можете сделать, так это сделать всплывающее окно на один символ шире, избегая тем самым переноса, который возникает из-за достижения ширины окна, например, путем изменения строки width+=8; на width+=8+1; в popupinfo.

person Armali    schedule 03.03.2014
comment
Хорошее воскрешение старого вопроса. С тех пор я пошел дальше, и этот проект в значительной степени не используется, но, оглядываясь назад, я полагаю, что еще один вариант - удалить любой символ новой строки, который ровно на 1_ символов после предыдущего или после начала строки... - person M_M; 12.03.2014
comment
Оглядываясь назад, я думаю, что я бы выбрал вариант удаления символов новой строки, хотя я сомневаюсь, что буду заниматься этим дальше. - person M_M; 18.03.2014