Python诅咒-输入文本时调整终端大小

Python诅咒-输入文本时调整终端大小,python,ncurses,curses,Python,Ncurses,Curses,我试图用诅咒做一个简单的GUI,但在调整屏幕大小和重画屏幕时遇到了一些问题。 这是我的密码: import curses import curses.textpad as textpad class editor (object): def __init__(self, stdscreen): self.screen = stdscreen self.height,self.width = self.screen.getmaxyx() s

我试图用诅咒做一个简单的GUI,但在调整屏幕大小和重画屏幕时遇到了一些问题。 这是我的密码:

import curses
import curses.textpad as textpad

class editor (object):
    def __init__(self, stdscreen):
        self.screen = stdscreen
        self.height,self.width = self.screen.getmaxyx()
        self.draw_screen()
        while True:
            # Check if the screen has been resized
            resize = curses.is_term_resized(self.height, self.width)
            if resize:
                self.height,self.width = self.screen.getmaxyx()
                self.draw_screen()
            curses.noecho()
            text = textpad.Textbox(self.text).edit(validate=self.validate)
            self.body.addstr(0,0, str(text), curses.A_NORMAL)
            self.body.refresh()
            self.text.erase()
    def draw_screen (self):
        self.screen.clear()
        self.header=self.screen.subwin(1,self.width,0,0)
        self.body=self.screen.subwin(self.height-3,self.width,1,0)
        self.text=self.screen.subwin(1,self.width,self.height-2,0)
        self.footer=self.screen.subwin(self.height-1,0)
        header_text = "{0:<{n}}".format("Header", n=self.width-1)
        self.header.addstr(0,0, header_text, curses.A_REVERSE)
        self.footer.addstr(0,0, "^W", curses.A_REVERSE)
        self.footer.addstr(0,2, " Quit", curses.A_NORMAL)
        self.header.noutrefresh()
        self.body.noutrefresh()
        self.footer.noutrefresh()
        self.text.noutrefresh()
        curses.doupdate()
    def validate (self, ch):
        # If resize event redraw screen
        if ch==curses.KEY_RESIZE:
            self.height,self.width = self.screen.getmaxyx()
            self.draw_screen()
        if ch==23: # ^w quit
            exit()
        else:
            return ch

if __name__=="__main__":
    curses.wrapper(editor)
将光标移回正确位置,但它不起作用

奖金: 如何保留在调整大小操作之前插入的文本并将其添加到调整大小的显示屏幕

编辑: 经过一段时间的调试,我想出了一个伪解决方案,这种解决方案虽然有效,但很难看,很粗糙

import curses
import curses.textpad as textpad

class my_textbox(textpad.Textbox):

    def edit(self, validate=None):
        while 1:
            ch = self.win.getch()
            # Return a list instead of a string if the last key was a resize
            if ch==curses.KEY_RESIZE:
                return[self.gather(),True]
            if validate:
                ch = validate(ch)
            if not ch:
                continue
            if not self.do_command(ch):
                break
            self.win.refresh()
        return self.gather()

class editor (object):
    def __init__(self, stdscreen):
        self.screen = stdscreen
        self.height,self.width = self.screen.getmaxyx()
        # Initialize a variable to store the previous text
        self.ptext=None
        curses.noecho()
        self.draw_screen()
        while True:
            # Check if the screen has been resized
            resize = curses.is_term_resized(self.height, self.width)
            if resize:
                self.height,self.width = self.screen.getmaxyx()
                self.draw_screen()
            text = my_textbox(self.text).edit(validate=self.validate)
            # If the window has been resized (aka textbox returned a list)
            if isinstance (text, list):
                text=text[0]
                # Store the previous text
                self.ptext=text.strip()
                continue
            self.body.addstr(0,0, str(text), curses.A_NORMAL)
            self.body.refresh()
            self.text.erase()
    def draw_screen (self):
        self.screen.clear()
        self.header=self.screen.subwin(1,self.width,0,0)
        self.body=self.screen.subwin(self.height-3,self.width,1,0)
        self.text=self.screen.subwin(1,self.width,self.height-2,0)
        self.footer=self.screen.subwin(self.height-1,0)
        header_text = "{0:<{n}}".format("Header", n=self.width-1)
        self.header.addstr(0,0, header_text, curses.A_REVERSE)
        # If there was text previous to resize
        if self.ptext:
            # To prevent _curses.error: addwstr() returned ERR
            # when shrinking window cut out the last character
            # (!) Raises ERR anyway when shrinking with double click from
            # titlebar, also, when resizing is too fast, ptext become a series of ^?
            if len(self.ptext)<self.width-1:
                self.text.addstr(0,0,self.ptext.strip())
            else:
                self.ptext=self.ptext[:self.width-1]
                self.text.addstr(0,0,self.ptext.strip())
        self.footer.addstr(0,0, "^W", curses.A_REVERSE)
        self.footer.addstr(0,2, " Quit", curses.A_NORMAL)
        self.header.noutrefresh()
        self.body.noutrefresh()
        self.footer.noutrefresh()
        self.text.noutrefresh()
        curses.doupdate()

    def validate (self, ch):
        if ch==23: # ^w quit
            exit()
        else:
            return ch

if __name__=="__main__":
    curses.wrapper(editor)
我所做的:

我重新定义了Textbox类的edit方法,以便在调整窗口大小时,它返回一个列表而不是字符串

在输入循环中,当窗口调整大小时,存储上一个文本,并开始新的循环

如果存在上一个文本,绘图功能会将其添加到子窗口中

注:

双击标题栏调整大小将抛出错误,如果调整太快,字符串将替换为垃圾^?,垃圾在被诅咒转换之前实际上是2^64-1


我想,因为ncurses的大部分功能都是在不可调整大小的终端的情况下创建的,所以实现毕竟是有意义的,但至少对于像我这样的python新手来说,一点也不直观。

描述听起来不错:应用程序必须重新布局文本并重新绘制屏幕内容

要做到这一点,它必须记录信息。其中一些是预定义的,例如此行中的标题

header_text = "{0:<{n}}".format("Header", n=self.width-1)
以及任何窗口,例如使用newwin创建的窗口。Python的类就是这样做的

尤其是诅咒,Python使用的ncurses支持一个名为的准窗口,在某些情况下可以使用它。但是它的textpad类并不容易使用,因为刷新pad的底层调用与窗口调用不同

然而,这需要一些实际工作,您可以创建一个与您想要管理的屏幕一样大的键盘,并使textpad成为该屏幕的子屏幕,然后独立于resizeterm进行重新布局。从ncurses复制的相关注释的Python文档:

resizeterm使用的后端功能,执行大部分工作;调整窗口大小时,resize_term blank将填充扩展的区域。调用应用程序应使用适当的数据填充这些区域。resize_term函数尝试调整所有窗口的大小。但是,由于PAD的调用约定,如果不与应用程序进行额外交互,则无法调整这些PAD的大小


谢谢你的建议,我做了更多的实验,我不确定问题是窗口被截断了。我已经用我发现的更新了这个问题。我想我可以用垫子做一些测试,但这似乎真的需要很多工作。
header_text = "{0:<{n}}".format("Header", n=self.width-1)
self.header=self.screen.subwin(1,self.width,0,0)