Я пытаюсь изучить библиотеку 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;
}
Ваш первый инстинкт был верным: getch()
делает неявный refresh()
, В частности, getch()
эквивалентно wgetch(stdscr)
так что это неявное wrefresh(stdscr)
— обновление окна (stdscr
) что вы не используете в противном случае, это просто происходит, чтобы заполнить экран. Причина того, что последующие вызовы не имеют никакого эффекта с того момента, заключается в том, что stdscr
что касается curses, то оно уже обновлено, поскольку после этого вы никогда не пишете в него (не говоря уже о том, что его содержимое было перезаписано на реальном экране).
Решение либо позвонить refresh()
явно вверху, перед тем как начать рисовать; или, мое предпочтение, позвонить wgetch()
в другом окне (в зависимости от того, что наиболее подходит) вместо getch()
и игнорировать существование stdscr
полностью. Просто помните, что все функции, которые не позволяют вам указать окно — getch()
, refresh()
и т. д. — действительно вызовы их «w» эквивалентов, с stdscr
в качестве неявного параметра окна.
По умолчанию 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()
чтобы быть неблокирующим, способ сделать это состоит в том, чтобы установить проклятия для режима нодли в окне по умолчанию.
С
getch()
,wgetch()
,mvgetch()
, а такжеmvwgetch()
функции, символ читается из терминала, связанного с
окно. В режиме нодлаев, если нет ожидающего ввода, значениеERR
возвращается В режиме задержки программа будет зависать до тех пор, пока система
передает текст в программу.
Так что звоните:
nodelay(stdscr, TRUE);
если ты хочешь getch()
быть неблокирующим; это вернется ERR
если ни одна клавиша не была нажата.
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 «бесполезным», за исключением того факта, что вы все равно можете сделать в консоли быструю графику, которая может быть сделано с небольшим навыком без использования какой-либо библиотеки. Вы поймете, что я имею в виду, если сделаете небольшую анимацию в этом меню, например, движущийся курсор, управляемый вашей клавиатурой и так далее. В основном, проклятия в основном используются только из-за его возможностей задержки, благодаря чему в консоли все выглядит более естественно, поэтому они не мерцают, особенно когда речь идет о деталях / анимациях, генерируемых через повторяющиеся циклы.