诅咒库:为什么 getch() 会清除我的屏幕
curses library: why does getch() clear my screen?
我正在尝试用C++学习curses库(pdcurses,因为我在Windows操作系统中)。我有一个程序显示 3 个窗口,然后是一个 while 循环,根据 getch() 捕获的按键进行一些处理。按下 F1 键时,循环将退出。
但是,尽管使用 wrefresh() 刷新了所有三个窗口,但在我第一次按键之前没有任何内容出现。如果没有 while 循环,一切都显示正常。我做了许多测试,就像第一次调用getch()会完全清除屏幕,但不会清除后续的屏幕。
我的问题是:我错过了什么?起初,我在想也许 getch() 正在调用隐式刷新(),但是为什么后续调用它的行为不相同呢?
提前非常感谢您的帮助。
这是代码。
#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
已经是最新的,因为在那之后你再也不会写信给它(不要介意它的内容在实际屏幕上被覆盖了)。
解决方案是在开始绘制之前在顶部显式调用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()
是非阻塞的,那么这样做的方法是在默认窗口中为 nodelay 模式设置 curses。
来自 pdcurses 文档:
随着
getch()
、wgetch()
、mvgetch()
和mvwgetch()
函数,从与 窗。在 nodelay 模式下,如果没有输入等待,则值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,你不再需要那个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 的使用变得"无用",除了您仍然可以在控制台中制作一些快速图形的事实,这可以通过一点技巧制作而无需使用任何库。如果你在该菜单中制作一个小动画,比如由键盘驱动的移动光标等等,你就会明白我的意思。基本上,诅咒大多只是因为它的延迟功能而被使用,使事情在控制台中看起来更自然,因此它们不会闪烁,尤其是在涉及通过重复循环生成的细节/动画时。
- 我的神经网络不起作用 [XOR 问题]
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 我的字符计数代码计算错误.为什么
- 为什么我的C#代码在调用回C++COM直到Task时会暂停.等待/线程.加入
- cmake在我的项目中所需的所有静态库都不成功
- 为什么我的代码在输出中增加了93天
- 我的简单if-else语句是如何无法访问的代码
- 为什么我的for循环不能正确获取argv
- 我的项目不会像"undefined reference to `grpc::g_core_codegen_interface'"那样使用未定义的引用错误进行编译
- 0-1背包代码中的错误.我的代码中有什么错误
- 当我的阵列太大时出现分段错误
- 如何确认我的constexpr表达式实际上已经在编译时执行
- 为什么二进制搜索在我的测试中不起作用
- 如何指定我希望我的LIB链接到的DLL文件?-Visual Studio 2019
- SDL_ttf清除我之前和将来的所有渲染
- 为什么Visual Studio正在清除我的一串反斜杠
- 清除临时列表而不清除我将其分配到的位置
- 当我写入我的文件时,它会清除该文件中以前的所有数据
- 为什么我的编译器在尝试清除 CIN 缓冲区时抱怨
- 诅咒库:为什么 getch() 会清除我的屏幕