pythonpython-3.xcursespython-curses

Animation using pads in curses


I would like to move a curses pad across the screen, but I can't figure out a way to automatically erase the pad from the previous position in the screen without erasing the contents of the pad. I don't want to have to redraw the pad every time I move it. Here's my test program:

import curses
import time

def main(stdscr):
  pad = curses.newpad(10, 10)
  ch = ord('A')
  pad.addch(4, 4, ch)
  for y in range(0, 10):
    for x in range(0, 10):
      print("adding pad at {y},{x}")
      try:
        pad.insch(y, x, ch)
      except:
        pass
      if x % 9 == 0:
        ch += 1
  pad.refresh(0, 0, 0, 0, 10, 10)
  time.sleep(2)
  pad.refresh(0, 0, 1, 1, 11, 11)
  time.sleep(2)
  pad.refresh(0, 0, 2, 2, 12, 12)
  time.sleep(2)

curses.wrapper(main)

At the end of this script, the window looks like:

AAAAAAAAAA
BAAAAAAAAAA
CBAAAAAAAAAA
DCBBBBBBBBBB
EDCCCCCCCCCC
FEDDDDDDDDDD
GFEEEEEEEEEE
HGFFFFFFFFFF
IHGGGGGGGGGG
JIHHHHHHHHHH
 JIIIIIIIIII
  JJJJJJJJJJ  

The first two lines and the first two characters of each line are leftover from previous pad displays. I want these erased.

I can create a different pad with the same dimensions and use it to erase the block from the screen:

def main(stdscr):
  pad = curses.newpad(10, 10)
  erasepad = curses.newpad(10, 10)
  ch = ord('A')
  pad.addch(4, 4, ch)
  for y in range(0, 10):
    for x in range(0, 10):
      print("adding pad at {y},{x}")
      try:
        pad.insch(y, x, ch)
      except:
        pass
      if x % 9 == 0:
        ch += 1
  pad.refresh(0, 0, 0, 0, 10, 10)
  time.sleep(2)
  erasepad.refresh(0, 0, 0, 0, 10, 10)
  pad.refresh(0, 0, 1, 1, 11, 11)
  time.sleep(2)
  erasepad.refresh(0, 0, 1, 1, 11, 11)
  pad.refresh(0, 0, 2, 2, 12, 12)
  time.sleep(2)

That's workable for my application, but is there a more efficient way? This requires me to create two pads for every animation block, and to completely erase every pad every time.


Solution

  • That's roughly the case. The sample code is inefficient however, doing extra repainting. Take a look at noutrefresh and doupdate (to replace those refresh calls), and replace the time.sleep with napms (again, to improve performance).