Python ncurses: Doesn't show screen until first key-press, even though refresh is first

徘徊边缘 提交于 2020-01-04 06:54:19

问题


The code below lets you walk around a small grid on the screen using the arrow keys putting "." where you've explored or been next to. Even though I have my refresh before the first getch (to get a key-stroke) the screen doesn't first display anything until you've moved off your starting position. Shouldn't the addstr followed by refresh immediately show and then the getch waits after that? I even tried adding a stdscr.refresh(), but that didn't help either. How do I get the screen to refresh immediately before waiting for the first key-stroke?

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)

回答1:


The docs are broken. I'd used curses back in the day, but libncurses is new to me.

My first hint came from ncurses(3):

The ncurses library permits manipulation of data structures, called windows, which can be thought of as two-dimensional arrays of characters representing all or part of a CRT screen. A default window called stdscr, which is the size of the terminal screen, is supplied. Others may be created with newwin. … Special windows called pads may also be manipulated. These are windows which are not constrained to the size of the screen and whose contents need not be completely displayed.

But then refresh(3) got decidedly evasive:

The routine wrefresh works by first calling wnoutrefresh, which copies the named window to the virtual screen, and then calling doupdate, which compares the virtual screen to the physical screen and does the actual update. … The phrase "copies the named window to the virtual screen" above is ambiguous. What actually happens is that all touched (changed) lines in the window are copied to the virtual screen. This affects programs that use overlapping windows; it means that if two windows overlap, you can refresh them in either order and the overlap region will be modified only when it is explicitly changed. [emphasis mine]

which prompted me to try adding

stdscr.refresh()

after your pad.refresh() which worked. And then I moved it further up start() to see if it was really needed on every pad modification. I moved it all the way up to the first point there is a stdscr to work with yielding:

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

which smacks of voodoo programming, but I'm not going to look at the innards of a 20-year old library made to cope with glass ttys to try to grok it.




回答2:


Add stdscr.refresh() sometime before the movement.refresh() to solve the issue.

By adding time.sleep(1) after the refresh statement, it does write to the screen, but then it disappears when stdscr.getch() is called, but only the first time. Probably has to do with some sort of delayed initialization of stdscr.

Calling stdscr.refresh() after the movement.refresh() has the same effect: The very first time through the loop stdscr.refresh() clears the screen, but not in subsequent times through the loop. By calling stdscr.refresh() early in the program it gets this weird first time refresh out of the way.




回答3:


When using a pad, for some reason—I don't know why—you have to call curses.doupdate after invoking the pad's refresh.



来源:https://stackoverflow.com/questions/16763701/python-ncurses-doesnt-show-screen-until-first-key-press-even-though-refresh-i

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!