библиотека curses: почему getch () очищает мой экран?

Я пытаюсь изучить библиотеку curses (pdcurses, как я в ОС Windows), на C ++.
У меня есть программа, которая отображает 3 окна, а затем цикл while для выполнения некоторой обработки, основанной на нажатиях клавиш, захваченных getch (). Цикл завершается при нажатии клавиши F1.

Тем не менее, несмотря на обновление всех трех окон с помощью wrefresh (), ничего не появляется до того, как я ввожу свое первое нажатие клавиши. Без цикла while все отображается нормально. Я сделал множество тестов, и это похоже на то, что первый вызов getch () полностью очистит экран, но не последующие.

Мой вопрос: что я пропустил? Сначала я думал, что, возможно, getch () вызывает неявную функцию refresh (), но тогда почему последующие вызовы не имеют такого же поведения?

Заранее большое спасибо за вашу помощь.

Вот код

#include <curses.h>

int main()
{
initscr();
raw();
keypad(stdscr, TRUE);
noecho();
curs_set(0);

WINDOW *wmap, *wlog, *wlegend;
int pressed_key;
int map_cursor_y = 10, map_cursor_x = 32;

wlog = newwin(5, 65, 0, 15);
wlegend = newwin(25, 15, 0, 0);
wmap = newwin(20, 65, 5, 15);

box(wmap, 0 , 0);
box(wlog, 0 , 0);
box(wlegend, 0 , 0);

mvwprintw(wlog, 1, 1, "this is the log window");
mvwprintw(wlegend, 1, 1, "legends");
mvwaddch(wmap, map_cursor_y, map_cursor_x, '@');

wrefresh(wlog);
wrefresh(wmap);
wrefresh(wlegend);

while ((pressed_key = getch()) != KEY_F(1))
{
/* process keys to move the @ cursor (left out because irrelevant) */

box(wmap, 0 , 0);
box(wlog, 0 , 0);
box(wlegend, 0 , 0);
wrefresh(wmap);
wrefresh(wlog);
wrefresh(wlegend);
}

endwin();
return 0;
}

7

Решение

Ваш первый инстинкт был верным: getch() делает неявный refresh(), В частности, getch() эквивалентно wgetch(stdscr)так что это неявное wrefresh(stdscr) — обновление окна (stdscr) что вы не используете в противном случае, это просто происходит, чтобы заполнить экран. Причина того, что последующие вызовы не имеют никакого эффекта с того момента, заключается в том, что stdscr что касается curses, то оно уже обновлено, поскольку после этого вы никогда не пишете в него (не говоря уже о том, что его содержимое было перезаписано на реальном экране).

Решение либо позвонить refresh() явно вверху, перед тем как начать рисовать; или, мое предпочтение, позвонить wgetch() в другом окне (в зависимости от того, что наиболее подходит) вместо getch()и игнорировать существование stdscr полностью. Просто помните, что все функции, которые не позволяют вам указать окно — getch(), refresh()и т. д. — действительно вызовы их «w» эквивалентов, с stdscr в качестве неявного параметра окна.

10

Другие решения

По умолчанию getch() блоки до нажатия клавиши. Измени свой цикл, чтобы быть do {} while(); цикл:

pressed_key = /* some value that will be benign or indicate that nothing has been pressed */

do {
/* process keys to move the @ cursor (left out because irrelevant) */

box(wmap, 0 , 0);
box(wlog, 0 , 0);
box(wlegend, 0 , 0);
wrefresh(wmap);
wrefresh(wlog);
wrefresh(wlegend);
} while ((pressed_key = getch()) != KEY_F(1));

Если тебе надо getch() чтобы быть неблокирующим, способ сделать это состоит в том, чтобы установить проклятия для режима нодли в окне по умолчанию.

Из документов pdcurses:

С getch(), wgetch(), mvgetch(), а также mvwgetch()
функции, символ читается из терминала, связанного с
окно. В режиме нодлаев, если нет ожидающего ввода, значение ERR
возвращается В режиме задержки программа будет зависать до тех пор, пока система
передает текст в программу.

Так что звоните:

nodelay(stdscr, TRUE);

если ты хочешь getch() быть неблокирующим; это вернется ERR если ни одна клавиша не была нажата.

1

getch () не очищает ваш экран, он просто делает то, что было сделано, блокируя ваш цикл while, ожидая получения символа с вашей клавиатуры.

Итак, вот кое-что, что может решить вашу проблему. Перед curses.h включите conio.h и сделайте ваш цикл while следующим образом:

do
{
box(wmap, 0 , 0);
box(wlog, 0 , 0);
box(wlegend, 0 , 0);
wrefresh(wmap);
wrefresh(wlog);
wrefresh(wlegend);
if(kbhit())
pressed_key = getch();
}while (pressed_key  != KEY_F(1));

Вот еще одно исправление для вас, которое также порадует @Kaz. На этот раз мы будем использовать windows.h вместо conio.h, и вам больше не нужен этот нажатый ключ. Сделайте ваш цикл while следующим образом:

do
{
/* process keys to move the @ cursor (left out because irrelevant) */
box(wmap, 0 , 0);
box(wlog, 0 , 0);
box(wlegend, 0 , 0);
wrefresh(wmap);
wrefresh(wlog);
wrefresh(wlegend);

}
while (!GetAsyncKeyState(VK_F1));

Между прочим, использование nodelay, как предлагается в другом ответе, решит текущую проблему, но в значительной степени сделает использование curses.h «бесполезным», за исключением того факта, что вы все равно можете сделать в консоли быструю графику, которая может быть сделано с небольшим навыком без использования какой-либо библиотеки. Вы поймете, что я имею в виду, если сделаете небольшую анимацию в этом меню, например, движущийся курсор, управляемый вашей клавиатурой и так далее. В основном, проклятия в основном используются только из-за его возможностей задержки, благодаря чему в консоли все выглядит более естественно, поэтому они не мерцают, особенно когда речь идет о деталях / анимациях, генерируемых через повторяющиеся циклы.

0
По вопросам рекламы [email protected]