curses在右下角调用addch时失败

问题描述 投票:0回答:5

我开始学习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)

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

python ncurses python-curses
5个回答
7
投票

这是预期的行为(怪癖),因为

addch
在添加字符后尝试 wrap 到下一行。 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).

5
投票

在 @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)

4
投票

window.insch(...)
可以将字符放置在窗口的右下角,而无需前进光标。该位置的任何字符都会向右移动,而不会导致错误。


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)

0
投票

这是 Brian 的 answer 的扩展。我决定根据书写位置(y,x)来选择方法

method = window.addch if (y+1, x+1) != window.getmaxyx() else window.inschr
method(y, x, char)

因为方法

addch
insch
具有相同的调用签名。

© www.soinside.com 2019 - 2024. All rights reserved.