Python Curses终端调整问题

时间:2017-07-25 04:47:19

标签: python terminal ncurses curses

将行打印到可以处理调整大小的终端窗口底部的正确方法是什么?

import curses
from curses import wrapper

def main(stdscr):
    inp = 0
    y,x = stdscr.getmaxyx()
    stdscr.clear()
    stdscr.nodelay(1)
    while inp != 48 and inp != 27:
        stdscr.addnstr(y-1,0, 'I AM KILL TERMINAL WHEN RESIZE AAAAAAAH', x)
        inp = stdscr.getch()

wrapper(main)

一旦我将终端的大小调整为较少的列,那么它尝试包裹到下一行的字符串的长度就会出错。我在文档中看不到有关禁用包装的任何内容。

我试图在addstr函数之前更新我的max y,x值。

while inp != 48 and inp != 27:

        if (y,x) != stdscr.getmaxyx():
            y,x = stdscr.getmaxyx()

        stdscr.addnstr(y-1,0, 'I AM KILL TERMINAL WHEN RESIZE AAAAAAAH', x)
        inp = stdscr.getch()

我也尝试过捕获SIGWINCH

while inp != 48 and inp != 27:

        def resize_handler(signum, frame):
            stdscr.erase()
            stdscr.refresh()
            termsize = shutil.get_terminal_size()
            curses.resizeterm(termsize[1],termsize[0])
            y,x = stdscr.getmaxyx()

        signal.signal(signal.SIGWINCH, resize_handler)

        stdscr.addnstr(y-1,0, 'I AM KILL TERMINAL WHEN RESIZE AAAAAAAH', x)
        inp = stdscr.getch()

但这些似乎都没有及早捕捉终端更新。

1 个答案:

答案 0 :(得分:3)

正确处理给定示例的 SIGWINCH 的方法是将stdscr.addnstrstdscr.getch调用封装在一个块中重写文本的代码(将字符数限制为现有的终端大小),在终端调整大小时执行此操作。

问题是stdscr.getch调用(实际上ncurses中的C函数正在执行工作)被中断。这就是在第一个例子中循环中执行的refresh。 ncurses'stdscr.getch应该从KEY_RESIZE调用中返回 stdscr.getch ,应用程序可以使用它来判断何时重新绘制内容。 (除了 OpenBSD 之外,其他功能因非技术原因而忽略了该功能)。

建立信号句柄可防止ncurses告诉应用程序终端已调整大小。阅读第二个例子,似乎ncurses库仍然在等待输入,已经完成了将addnstr文本放在屏幕上的刷新(从第一次调整大小之前)。

讨论Curses and resizing windows显示了一个陷阱:如果应用程序不会读取字符,则永远不会看到 KEY_RESIZE 。但是你的例子并没有这样做。我放弃了信号处理程序(除了妨碍它,它使用信号不安全的函数,它可以破坏python),并将第一个例子改为这样:

import curses
from curses import wrapper

def main(stdscr):
    inp = 0
    y,x = stdscr.getmaxyx()
    stdscr.clear()
    stdscr.nodelay(1)
    while inp != 48 and inp != 27:
        while True:
            try:
                stdscr.addnstr(y-1,0, 'I AM KILL TERMINAL WHEN RESIZE AAAAAAAH', x)
            except curses.error:
                pass
            inp = stdscr.getch()
            if inp != curses.KEY_RESIZE:
                break
            stdscr.erase()
            y,x = stdscr.getmaxyx()

wrapper(main)