我正在尝试使用C ++学习curses库(pdcurses,就像我在Windows操作系统中一样)。 我有一个显示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;
}
答案 0 :(得分:10)
您的第一直觉是正确的:getch()
执行隐式refresh()
。具体来说,getch()
相当于wgetch(stdscr)
,因此它是一个隐含的wrefresh(stdscr)
- 更新您未使用的窗口(stdscr
),恰好填写屏幕。后续调用从那一点开始没有影响的原因是stdscr
已经是最新的,就诅咒而言,因为你之后从未写过它(更别提它的内容已被覆盖)在实际屏幕上。)
解决方案是在开始绘图之前在顶部显式调用refresh()
;或者,我的偏好是,在另一个窗口(以最合适的为准)上调用wgetch()
而不是getch()
,并完全忽略stdscr
的存在。请记住,所有不允许您指定窗口的函数 - getch()
,refresh()
等 - 实际上是对其“w”等效项的调用,stdscr
为隐式窗口参数。
答案 1 :(得分:1)
默认情况下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()
非阻塞,那么这样做的方法是在默认窗口中为nodelay模式设置curses。
使用
getch()
,wgetch()
,mvgetch()
和mvwgetch()
函数,从与之关联的终端读取字符 窗口。在nodelay模式下,如果没有输入等待,则值ERR
退回。在延迟模式下,程序将挂起直到系统 将文本传递给程序。
所以打电话:
nodelay(stdscr, TRUE);
如果您希望getch()
无阻塞;如果没有按下任何键,它将返回ERR
。
答案 2 :(得分:0)
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,你不再需要那个pressed_key了。像这样制作你的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“无用”,除了你仍然可以在控制台中做一些快速图形的事实,这可以通过一些技巧而不使用任何库来完成。如果您在该菜单中制作一个小动画,就像键盘驱动的移动光标等,你会明白我的意思。基本上诅咒主要是因为它的延迟功能,在控制台中看起来更自然,所以它们不会闪烁,特别是当涉及通过重复循环产生的细节/动画时。