【问题标题】:How to delete a subwindow in the python curses module如何在 python curses 模块中删除子窗口
【发布时间】:2013-01-28 21:48:41
【问题描述】:

我有一个使用子窗口的 curses 应用程序,但我似乎无法删除它们。

例如,这段代码不起作用:

import curses
def fill(window, ch):
    y, x = window.getmaxyx()
    s = ch * (x - 1)
    for line in range(y):
        window.addstr(line, 0, s)

def main(stdscr):
    fill(stdscr, 'M')
    stdscr.refresh()
    stdscr.getch()

    subwin = stdscr.subwin(1, 28, 20, 13)
    fill(subwin, 'J')
    subwin.refresh()
    subwin.getch()

    del subwin
    stdscr.touchwin()
    stdscr.refresh()
    stdscr.getch()

curses.wrapper(main)

当您运行此代码时,屏幕会填充“M”,然后当您按下某个键时,会创建一个子窗口并填充“J”。最后,当您再次按下某个键时,代码会删除子窗口并完全重绘屏幕。但是,那些Js还在。

经过一些实验,我发现调用 stdscr 的 clear() 方法会使子窗口消失,但我想将背景恢复原样,而不是将其清空和重写。 有谁知道可以做到这一点的方法吗?

【问题讨论】:

  • 有人知道这段代码是从哪里来的吗?是Alex the author?有趣的是,唯一真正的区别是subwin/newwin 问题...
  • 是的,我确实从那个问题中得到了代码。我发现它正在寻找我的答案。代码(就像您注意到的那样)只需要更改一个函数名称即可证明我的问题。我现在已经仔细检查了规则,我可能应该给出正确的归属。

标签: python curses


【解决方案1】:

您使用子窗口是否有充分的理由?如果您创建一个新的顶级窗口,则代码可以正常工作 - 只需将 stdscr.subwin 更改为 curses.newwin 即可按预期工作。

我不是 curses 专家,但我相信子窗口与其父窗口共享字符缓冲区,因此对其中一个的更改也会影响另一个。因此,如果您希望将窗口细分为逻辑区域(可能是菜单栏、主区域和状态栏),那么子窗口很有用。但是,如果您正在寻找更像是对话框或弹出菜单的东西,那么您需要的是一个全新的窗口(带有自己的单独缓冲区)。

我找不到任何同意或不同意我的 ncurses 的明确参考,但 man page for AIX 似乎证实了这一点:

回想一下,子窗口共享其父窗口缓冲区。通过父窗口或其任何子窗口对子窗口所覆盖区域中的共享窗口缓冲区所做的更改会影响共享该窗口缓冲区的所有窗口。

当然,这对于 ncurses 来说不是确定的,但我找不到任何相反的东西,它似乎确实可以解释观察到的行为。我还做了一个粗略的实验,在您的示例中的 subwin.getch() 行之后,我立即添加了这一行:

raise Exception(stdscr.instr(20, 15, 3))

在您的示例中,我得到JJJ 作为实际主窗口的内容。如果我改为使用curses.newwin() 而不是stdscr.subwin() 创建窗口,我会得到预期的MMM

我不知道有多少特定的 Python curses 资源,但是大多数关于 ncurses 的标准教程和文档对于这种级别非常有用。当我不得不在其中做一些工作时,this document 非常有用。如果您向下滚动到“示例”部分,您会看到菜单弹出窗口 不是 子窗口 - 他通过以下稍微模糊的解释暗示了这一点:

我们不希望这个新窗口覆盖之前在背景上写入的字符。菜单关闭后他们应该留在那里。这就是为什么菜单窗口不能创建为 stdscr 的子窗口的原因。

另外,我记得同时使用 stdscr 和您自己的窗口可能会导致问题 - the "official" ncurses introductionsome warnings 关于这类事情。它还建议完全避免重叠窗口,因为它们显然容易出错,但我不记得它们对短期瞬态模态对话框有任何问题(这是我放置它们的唯一用途)。当然,仅仅因为我的简单用例没有暴露任何问题并不意味着没有任何问题。然而,在像 ncurses 这样复杂的事情中,我可以看到让事情尽可能简单的智慧。

我希望这会有所帮助。正如我所说,我绝不是诅咒专家,但希望这能让你更进一步。

【讨论】:

  • 谢谢,这似乎正是我需要的信息。我使用 subwin 是因为它听起来像我打算做的,但实际定义似乎与我想象的略有不同。
  • 是的,curses 有时有点奇怪,而且它肯定不是文档最好的 API。一旦添加了通过另一个 API(Python 层)进行间接访问的事实,您可能会发现很难找到可靠的参考信息 - 我建议您编写一些小测试应用程序并在您使用新的应用程序时尝试验证您的假设功能。
【解决方案2】:

这段代码有两个问题。

首先,正如上一张海报所指出的,子窗口与父窗口共享一个缓冲区,所以如果你想要一个完全独立的窗口,你应该使用curses.newwin()

其次,使用del 删除窗口是有问题的,因为它依赖于引用计数/垃圾收集才能正常工作。 (一方面,您必须删除对窗口的所有 引用才能使其工作。)我建议使用curses.panel 模块来显式显示/隐藏窗口。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-04-09
    • 1970-01-01
    • 1970-01-01
    • 2021-11-20
    • 2011-02-04
    • 1970-01-01
    • 2014-11-30
    相关资源
    最近更新 更多