诅咒库:为啥 getch() 清除我的屏幕?
Posted
技术标签:
【中文标题】诅咒库:为啥 getch() 清除我的屏幕?【英文标题】:curses library: why does getch() clear my screen?诅咒库:为什么 getch() 清除我的屏幕? 【发布时间】:2013-11-13 22:45:01 【问题描述】:我正在尝试使用 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;
【问题讨论】:
Curses library, C , getch without clearing screen的可能重复 【参考方案1】:您的第一直觉是正确的:getch()
隐含了refresh()
。具体来说,getch()
等价于wgetch(stdscr)
,所以它是一个隐含的wrefresh(stdscr)
——更新一个你没有使用的窗口(@987654326@),它恰好填满了屏幕。从那时起后续调用没有任何影响的原因是,就 curses 而言,stdscr
已经是最新的,因为在那之后你再也没有写过它(不要介意它的内容已经被覆盖在实际屏幕)。
解决方案是在开始绘制之前在顶部显式调用refresh()
;或者,我更喜欢在不同的窗口(以最合适的方式)调用wgetch()
,而不是getch()
,并完全忽略stdscr
的存在。请记住,所有不允许您指定窗口的函数——getch()
、refresh()
等——实际上都是调用它们的“w”等价物,stdscr
作为隐式窗口参数。
【讨论】:
在从 newwin 分配的窗口上调用 wgetch 似乎仍然可以刷新我的屏幕 - 有什么想法吗?郁闷,因为我想清屏然后收集输入,然后根据输入绘制,在某些情况下会导致闪烁 抱歉,我不应该在凌晨 3 点上班。这确实是我的错,我忘记将我的nodelay
调用更改为新的输入窗口,它仍在我的stdscr
上,所以当我要求输入时,它在那里暂停执行。无论如何,谢谢!【参考方案2】:
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 的使用“无用”,除了你仍然可以在控制台中做一些快速图形的事实,可以在不使用任何库的情况下通过一点技巧来制作。如果您在该菜单中制作一些动画,例如由键盘驱动的移动光标等,您就会明白我的意思。基本上curses主要是因为它的延迟能力,让东西在控制台中看起来更自然,所以它们不会闪烁,特别是当涉及到通过重复循环生成的细节/动画时..
【讨论】:
将curses(起源于Unix终端世界的屏幕控制库,现在或多或少独立于平台)与conio.h(起源于Borland C的DOS/Bios接口)完全混合... 傻。 是的,但是 kbhit() 是暂时想到的,它来自 conio【参考方案3】:默认情况下,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。
From the pdcurses docs:
使用
getch()
、wgetch()
、mvgetch()
和mvwgetch()
函数,从与 窗户。在nodelay模式下,如果没有输入等待,则值为ERR
被退回。在延迟模式下,程序会一直挂起,直到系统 将文本传递给程序。
所以调用:
nodelay(stdscr, TRUE);
如果您希望getch()
是非阻塞的;如果没有按下任何键,它将返回ERR
。
【讨论】:
以上是关于诅咒库:为啥 getch() 清除我的屏幕?的主要内容,如果未能解决你的问题,请参考以下文章
为啥我不能在 python 诅咒窗口中将str()添加到最后一行/列?