2

下面的代码让您可以使用放置“。”的箭头键在屏幕上的一个小网格中走动。您探索过或去过的地方。即使我在第一次 getch 之前进行了刷新(以获得击键),屏幕也不会首先显示任何内容,直到您离开起始位置。addstr 后跟 refresh 不应该立即显示,然后 getch 等待吗?我什至尝试添加 stdscr.refresh(),但这也无济于事。如何在等待第一次击键之前立即刷新屏幕?

import curses

def start(stdscr):
    curses.curs_set(0)
    movement = curses.newpad(10, 10)

    cur_x, cur_y = 5, 5

    while True:
        movement.addstr(cur_y, cur_x, '@')
        for (x_off, y_off) in [(-1,0),(1,0),(0,-1),(0,1)]:
            movement.addstr(cur_y + y_off, cur_x + x_off, '.')
        movement.refresh(1, 1, 0, 0, 7, 7) #Nothing is displayed until after the first key-stroke

        key_stroke = stdscr.getch()
        move_attempt = False
        if 0 < key_stroke < 256:
            key_stroke = chr(key_stroke)
        elif key_stroke == curses.KEY_UP and cur_y > 1:
            cur_y -= 1
        elif key_stroke == curses.KEY_DOWN and cur_y < 8:
            cur_y += 1
        elif key_stroke == curses.KEY_LEFT and cur_x > 1:
            cur_x -= 1
        elif key_stroke == curses.KEY_RIGHT and cur_x < 8:
            cur_x += 1
        else:
            pass

if __name__ == '__main__':
    curses.wrapper(start)
4

4 回答 4

7

文档坏了。我以前用过 curses,但 libncurses 对我来说是新的。

我的第一个提示来自ncurses(3)

ncurses 库允许对称为窗口的数据结构进行操作,可以将其视为代表 CRT 屏幕的全部或部分的二维字符数组。提供了一个名为 stdscr 的默认窗口,它是终端屏幕的大小。其他的可以用 newwin 创建。... 也可以操纵称为垫的特殊窗口。这些窗口不受屏幕大小的限制,其内容不需要完全显示。

但随后refresh(3)明显回避:

wrefresh 例程首先调用 wnoutrefresh,将命名窗口复制到虚拟屏幕,然后调用 doupdate,将虚拟屏幕与物理屏幕进行比较并进行实际更新。... 上面的“将命名窗口复制到虚拟屏幕”这句话是模棱两可的。实际发生的是窗口中所有触摸(更改)的行都被复制到虚拟屏幕上。这会影响使用重叠窗口的程序;这意味着如果两个窗口重叠,您可以按任一顺序刷新它们,并且重叠区域只有在显式更改时才会被修改。[强调我的]

这促使我尝试添加

stdscr.refresh()

在你pad.refresh()工作之后。然后我将它进一步向上移动start(),看看是否真的需要在每次垫修改时使用它。我将它一直移动到第一个点,stdscr可以使用 yield:

def start(stdscr):
    stdscr.refresh()
    curses.curs_set(0)
    …

这有点伏都教编程的味道,但我不会看一个有 20 年历史的图书馆的内部结构,它是为应对玻璃 ttys 而设计的,试图去摸索它。

于 2013-05-27T04:27:16.433 回答
2

在解决问题stdscr.refresh()之前添加一些时间。movement.refresh()

通过time.sleep(1)在刷新语句之后添加,它确实会写入屏幕,但是在stdscr.getch()被调用时它会消失,但只是第一次。可能与 stdscr 的某种延迟初始化有关。

stdscr.refresh()在之后调用movement.refresh()具有相同的效果:第一次通过循环stdscr.refresh()清除屏幕,但在随后的循环中不会。通过在程序的早期调用stdscr.refresh(),它可以避免这种奇怪的第一次刷新。

于 2013-05-27T02:02:52.670 回答
0

使用 pad 时,出于某种原因——我不知道为什么——你必须curses.doupdate在调用 pad 的refresh.

于 2013-05-26T22:30:51.020 回答
0

在为我解决问题window.nodelay(1)之前添加。while

于 2021-05-07T19:38:53.827 回答