Python Curses 处理窗口(终端)调整大小

34

这实际上是两个问题:

  • 如何调整curses窗口的大小,以及
  • 在curses中如何处理终端大小的改变?

是否可能知道窗口何时改变大小?

我真的找不到任何好的文档,甚至在http://docs.python.org/library/curses.html上也没有涉及。

5个回答

36

在终端调整大小事件发生时,会产生键码。因此你可以将终端调整大小作为curses程序标准主循环的一部分处理,在使用getch等待输入时处理。


2
这是正确的,但只有在使用--enable-sigwinch编译ncurses时才有效。特别地,Debian和Ubuntu中的libncurses没有打开它;我不确定为什么。 - the paul
@thepaul:至少在我的Ubuntu 12.04中,当我调整终端仿真器窗口大小时,我会得到curses.KEY_RESIZE代码。 - MestreLion
好的,我很高兴他们修复了那个问题。 - the paul

10

我通过以下几个步骤让我的Python程序调整终端大小。

# Initialize the screen
import curses

screen = curses.initscr()

# Check if screen was re-sized (True or False)
resize = curses.is_term_resized(y, x)

# Action in loop if resize is True:
if resize is True:
    y, x = screen.getmaxyx()
    screen.clear()
    curses.resizeterm(y, x)
    screen.refresh()

我在编写程序时发现将屏幕放入一个独立的类中并定义所有这些函数非常有用。这样,我只需调用 Screen.resize() 就可以完成所有操作。


你能添加必要的内容使得这段代码自包含吗?例如,我不确定“screen”是什么。 - Don Hatch
1
@DonHatch 希望这是你要找的。如果你需要的话,这里还有一个不错的小教程。https://docs.python.org/3/howto/curses.html - jarsever
他的意思是,如果你只是复制粘贴代码进行测试,那么你的代码不会起作用,因为有很多东西缺失。 - answerSeeker
4
resize = curses.is_term_resized(y, x)中,你从哪里获取y、x的值?是旧的终端大小吗?如果是,你如何获取终端的大小?对我来说,screen.getmaxyx()似乎没有返回更新后的大小。当我更改命令行的大小时,它仍然保持不变... (注:已将原文的“command line”翻译成“命令行”,因为根据上下文大概率是指终端窗口) - Brambor

5

我使用了这里的代码。

在我的curses脚本中,我没有使用getch()函数,因此无法对KEY_RESIZE做出反应。

因此,该脚本会对SIGWINCH做出反应,并在处理程序中重新初始化curses库。这当然意味着你需要重新绘制所有内容,但我找不到更好的解决方案。

以下是一些示例代码:

from curses import initscr, endwin
from signal import signal, SIGWINCH
from time import sleep

stdscr = initscr()

def redraw_stdscreen():
    rows, cols = stdscr.getmaxyx()
    stdscr.clear()
    stdscr.border()
    stdscr.hline(2, 1, '_', cols-2)
    stdscr.refresh()

def resize_handler(signum, frame):
    endwin()  # This could lead to crashes according to below comment
    stdscr.refresh()
    redraw_stdscreen()

signal(SIGWINCH, resize_handler)

initscr()

try:
    redraw_stdscreen()

    while 1:
        # print stuff with curses
        sleep(1)
except (KeyboardInterrupt, SystemExit):
    pass
except Exception as e:
    pass

endwin()

在信号处理程序中调用endwin/initscr是导致核心转储的好方法。 - Thomas Dickey
@ThomasDickey 谢谢你的信息。我已经从信号处理程序中删除了一个initscr(),这可能并没有太大的改进。在接受的答案中的c代码建议使用endwin()后跟refresh()。我想知道,如果是python3,它会通知用户关于核心转储吗?如果是的话,当我疯狂地调整终端大小时,我到目前为止还没有遇到过这种情况。 - JackLeEmmerdeur

1

当我使用curses.wrapper()时,这对我很有效:

if stdscr.getch() == curses.KEY_RESIZE:
    curses.resizeterm(*stdscr.getmaxyx())
    stdscr.clear()
    stdscr.refresh()

1
我尝试在 VS Code 中使用终端,但很可能由于无限重复的 curses.KEY_RESIZE 事件而卡在了循环中。调用 curses.flushinp() 没有帮助。不过这个答案还是对我帮助很大的。 - qdbp
@qdbp 无限重复的 curses.KEY_RESIZE 事件?如果您不能依赖于 stdscr.getch(),我猜您只能跟踪当 stdscr.getmaxyx() 返回新值时。 - Mike Conigliaro
在我的Curses/Python安装中,函数名是resize_term而不是resizeterm。此外,您提到的Curses文档页面中也是使用的resize_term - undefined

-2

这不正确。这是一个仅限于 ncurses 的扩展。问题是关于 curses 的。为了以符合标准的方式进行操作,您需要自己捕获 SIGWINCH 并安排屏幕重新绘制。


7
这段话在讨论 Python 的 curses 库,它实际上是对 ncurses 库的封装。 - Sandy Chapman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接