我试图用诅咒来做一个简单的图形用户界面,但是在调整屏幕大小和重新绘制屏幕时,我遇到了一些问题。 这是我的代码:
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)
当没有调整终端大小时,它的工作方式与预期一样,但是当我放大终端窗口时,当页眉和页脚分别移动到顶行和底行时,光标将保持在上一个位置,直到按Enter键接受字符串。 收缩时也一样,只是在这种情况下,光标移到页脚上,并返回页脚的内容。 尝试调试这个问题时,我发现子窗口似乎移动得很好,但是光标并没有随它们一起移动。我也试过
^{pr2}$将光标移回正确的位置,但它不起作用。在
奖金: 如何保留在调整大小操作之前插入的文本并将其添加到已调整大小的显示屏幕上?在
编辑: 经过更多的调试之后,我想出了一个“有点”管用的伪解决方案(但又难看又难看)。在
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,在被诅咒转换之前)。在
我想,因为(n)curses的大部分功能都是用不可调整大小的终端创建的,所以这个实现毕竟是有意义的,但至少对于像我这样对python比较陌生的人来说,根本就不直观。在
描述听起来不错:应用程序必须重新布局文本并重新绘制屏幕内容。在
要做到这一点,它必须保留信息的记录。其中一些是预定义的,例如
"Header"
在这一行中但是如果屏幕变小,子窗口的内容可能会丢失(因为ncurses中的^{} 将截断这些窗口):
^{pr2}$以及使用
newwin
创建的任何窗口。Python的textpad类可以做到这一点。在curses(特别是Python使用的ncurses)支持一个名为"pad"的准窗口,在某些情况下可以使用它。但它的textpad类不易使用(因为刷新pad的底层调用与窗口的调用不同)。在
然而(这需要一些实际的工作),您可以创建一个与您想要管理的屏幕一样大的pad,并使textpad成为它的子级,然后独立于} 注释的文档(从ncursesmanual复制):
resizeterm
进行自己的重新布局。Python有关^{相关问题 更多 >
编程相关推荐