诅咒库:为啥 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)——更新一个你没有使用的窗口(@98​​7654326@),它恰好填满了屏幕。从那时起后续调用没有任何影响的原因是,就 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()添加到最后一行/列?

为啥我需要两个 _getch() 才能获得正确的值? [复制]

如何使用带有诅咒的终端调色板

python 诅咒 tty 屏幕闪烁

为啥我的清除命令搞砸了?

为啥我的 Mobile Safari 缓存不会清除?