在右下角调用addch时,curses失败了

时间:2016-04-03 15:53:56

标签: python ncurses python-curses

我开始学习Python中的curses。我在Mac OS X上使用Python 3.5。当我尝试在右下角写入时,程序崩溃并出现以下错误:

$ python ex_curses.py
[...]
  File "ex_curses.py", line 19, in do_curses
    screen.addch(mlines, mcols, 'c')
  _curses.error: add_wch() returned ERR

示例程序是:

import curses

def do_curses(screen):
    curses.noecho()
    curses.curs_set(0)
    screen.keypad(1)

    (line, col) = 12, 0
    screen.addstr(line, col, "Hello world!")
    line += 1
    screen.addstr(line, col, "Hello world!", curses.A_REVERSE)

    screen.addch(0, 0, "c")

    (mlines, mcols) = screen.getmaxyx()
    mlines -= 1
    mcols -= 1
    screen.addch(mlines, mcols, 'c')

    while True:
        event = screen.getch()
        if event == ord("q"):
            break
    curses.endwin()

if __name__ == "__main__":
    curses.wrapper(do_curses)

我有一种感觉,我错过了一些明显的东西,但我不知道是什么。

4 个答案:

答案 0 :(得分:4)

这是预期的行为(怪癖),因为addch在添加字符后尝试换行到下一行。有comment in lib_addch.c处理此问题:

/*
 * The _WRAPPED flag is useful only for telling an application that we've just
 * wrapped the cursor.  We don't do anything with this flag except set it when
 * wrapping, and clear it whenever we move the cursor.  If we try to wrap at
 * the lower-right corner of a window, we cannot move the cursor (since that
 * wouldn't be legal).  So we return an error (which is what SVr4 does).
 * Unlike SVr4, we can successfully add a character to the lower-right corner
 * (Solaris 2.6 does this also, however).
 */

答案 1 :(得分:3)

为未来的读者。在@Thomas Dickey回答之后,我在代码中添加了以下代码段。

try: 
    screen.addch(mlines, mcols, 'c')
except _curses.error as e:
    pass 

现在我的代码如下:

import curses
import _curses

def do_curses(screen):
    curses.noecho()
    curses.curs_set(0)
    screen.keypad(1)

    (line, col) = 12, 0
    screen.addstr(line, col, "Hello world!")
    line += 1
    screen.addstr(line, col, "Hello world!", curses.A_REVERSE)

    screen.addch(0, 0, "c")

    (mlines, mcols) = screen.getmaxyx()
    mlines -= 1
    mcols -= 1
    try:
        screen.addch(mlines, mcols, 'c')
    except _curses.error as e:
        pass

    while True:
        event = screen.getch()
        if event == ord("q"):
            break
    curses.endwin()

if __name__ == "__main__":
    curses.wrapper(do_curses)

答案 2 :(得分:1)

window.insch(...)可以在窗口的右下方放置一个字符,而无需前进光标。该位置上的任何字符都会在不引起错误的情况下向右碰撞。

答案 3 :(得分:0)

这是一种奇异的解决方案,它利用了curses实际上可以在绘制边框时绘制右下角的字符(而不会引发异常)的事实。查看完整的示例:

# -*- coding: utf-8 -*-
import curses


def addch_bottom_right(window, ch):
    """
    Somehow, the underlying ncurses library has an issue
    with writing a char into bottom-right corner
    (see the https://stackoverflow.com/a/36389161 for example).

    But we can use the workaround:
    - create a subwindow 1x1 of the current window in the bottom-right corner
    - draw a border of that window, consisting only of the desired character:
      for a 1x1 window, that border will consist exclusively of this single character.
    - refresh the screen to show your new 'window' with the 'border'.
    """
    print("Putting char '%s' in the bottom-right corner" % ch)
    beg_y, beg_x = window.getbegyx()
    max_y, max_x = window.getmaxyx()
    br_y = beg_y + max_y - 1
    br_x = beg_x + max_x - 1

    print('Coordinates of current window: %sx%s' % (br_y, br_x))
    w = window.subwin(1, 1, br_y, br_x)

    # only 'br' (bottom-right corner) gets printed for 1x1 box
    w.border(*([ch] * 8))
    w.noutrefresh()
    window.noutrefresh()
    curses.doupdate()


def demo(screen, show_border=True):
    """
    Try the workaround with three different windows nesting levels.

    Borders drawn here only to show where the windows are.
    """
    curses.curs_set(0)

    w = screen.subwin(8, 8, 10, 10)
    if show_border:
        w.border()
    addch_bottom_right(w, 'Window'[0])

    w2 = w.subwin(3, 3, 12, 12)
    if show_border:
        w2.box()
    addch_bottom_right(w2, 'Subwindow'[0])

    addch_bottom_right(screen, 'Main screen'[0])

    screen.getch()


if __name__ == '__main__':
    curses.wrapper(demo)