Python 诅咒终端调整大小问题

Python Curses Terminal Resize Issue

在可以处理调整大小的终端 window 底部打印一行的正确方法是什么?

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 函数之前更新我的最大 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()

但是这些似乎都没有足够早地捕获终端更新。

对于给定的示例,正确处​​理SIGWINCH的方法是包装stdscr.addnstrstdscr.getch 调用一个重绘文本的代码块(将字符数限制为现有的终端大小),在调整终端大小时经常这样做。

问题是 stdscr.getch 调用(实际上是 ncurses 中的 C 函数在做这项工作)被中断了。这就是第一个示例中在循环中执行的 refresh 。 ncurses 的 stdscr.getch 应该从 stdscr.getch 调用中返回一个 KEY_RESIZE,应用程序可以使用它来判断何时重绘。 (这适用于 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)