以下是一个使用'urwid'框架的非常简单的文本编辑器。不确定我是否选择了最好的框架来做文本编辑器,但这就是我正在尝试的。
但是我该如何改变呢?我想更改它以在用户添加一些文本时添加“未保存”,我知道在哪里添加,但是如何更新页脚属性?
我在这里找到了关于如何更改页脚文本的示例(它在 self.footer 中设置)但是如何重绘小部件?我一直在努力理解这一点。也许我应该回去使用诅咒?
http://urwid.org/reference/widget.html#urwid.Frame
在初始化函数中设置页脚:
class EditDisplay:
def __init__(self, name):
self.save_name = name
self.saved = ""
self.walker = LineWalker(name)
self.listbox = urwid.ListBox(self.walker)
self.footer_text = ('foot', [
"jEditor File: '",
self.save_name,
"'" ,
self.saved,
('key', "F5"), " save ",
('key', "F6"), " quit ",
('key', 'F7'), " delete "
])
self.footer = urwid.AttrMap(urwid.Text(self.footer_text),
"foot")
self.view = urwid.Frame(urwid.AttrMap(self.listbox, 'body'),
footer=self.footer)
完整文件:
“”“
text eidtor
Usage:
edit.py <filename>
"""
import os
import sys
import urwid
import urwid.raw_display
# Globals
class LineWalker(urwid.ListWalker):
"""ListWalker-compatible class for lazily reading file contents."""
def __init__(self, name):
self.file = open(name)
self.lines = []
self.focus = 0
def get_focus(self):
return self._get_at_pos(self.focus)
def set_focus(self, focus):
self.focus = focus
self._modified()
def get_next(self, start_from):
return self._get_at_pos(start_from + 1)
def get_prev(self, start_from):
return self._get_at_pos(start_from - 1)
def read_next_line(self):
"""Read another line from the file."""
next_line = self.file.readline()
if not next_line or next_line[-1:] != '\n':
# no newline on last line of file
self.file = None
else:
# trim newline characters
next_line = next_line[:-1]
expanded = next_line.expandtabs()
edit = urwid.Edit("", expanded, allow_tab=True)
edit.set_edit_pos(0)
edit.original_text = next_line
self.lines.append(edit)
return next_line
def _get_at_pos(self, pos):
"""Return a widget for the line number passed."""
if pos < 0:
# line 0 is the start of the file, no more above
return None, None
if len(self.lines) > pos:
# we have that line so return it
return self.lines[pos], pos
if self.file is None:
# file is closed, so there are no more lines
return None, None
assert pos == len(self.lines), "out of order request?"
self.read_next_line()
return self.lines[-1], pos
def split_focus(self):
"""Divide the focus edit widget at the cursor location."""
focus = self.lines[self.focus]
pos = focus.edit_pos
edit = urwid.Edit("",focus.edit_text[pos:], allow_tab=True)
edit.original_text = ""
focus.set_edit_text(focus.edit_text[:pos])
edit.set_edit_pos(0)
self.lines.insert(self.focus+1, edit)
def combine_focus_with_prev(self):
"""Combine the focus edit widget with the one above."""
above, ignore = self.get_prev(self.focus)
if above is None:
# already at the top
return
focus = self.lines[self.focus]
above.set_edit_pos(len(above.edit_text))
above.set_edit_text(above.edit_text + focus.edit_text)
del self.lines[self.focus]
self.focus -= 1
def combine_focus_with_next(self):
"""Combine the focus edit widget with the one below."""
below, ignore = self.get_next(self.focus)
if below is None:
# already at bottom
return
focus = self.lines[self.focus]
focus.set_edit_text(focus.edit_text + below.edit_text)
del self.lines[self.focus+1]
class EditDisplay:
palette = [
('body','default', 'default'),
('foot','dark gray', 'white', 'bold'),
('key','dark gray', 'white', 'underline'),
]
footer_text = ('', [])
def __init__(self, name):
self.save_name = name
self.saved = ""
self.walker = LineWalker(name)
self.listbox = urwid.ListBox(self.walker)
self.footer_text = ('foot', [
"jEditor File: '",
self.save_name,
"'" ,
self.saved,
('key', "F5"), " save ",
('key', "F6"), " quit ",
('key', 'F7'), " delete "
])
self.footer = urwid.AttrMap(urwid.Text(self.footer_text),
"foot")
self.view = urwid.Frame(urwid.AttrMap(self.listbox, 'body'),
footer=self.footer)
def main(self):
self.loop = urwid.MainLoop(self.view, self.palette,
unhandled_input=self.unhandled_keypress)
self.loop.run()
def unhandled_keypress(self, k):
"""Last resort for keypresses."""
if (k != "f5" or k != "f6" or k != "f7" ):
self.saved = " (unsaved) "
# Want to change the footer text here
self.text_widget.set_text('No number set')
if k == "f5":
self.saved = ""
self.save_file()
elif k == "f6":
raise urwid.ExitMainLoop()
elif k == "f7":
os.remove(self.save_name)
elif k == "delete":
# delete at end of line
self.walker.combine_focus_with_next()
elif k == "backspace":
# backspace at beginning of line
self.walker.combine_focus_with_prev()
elif k == "enter":
# start new line
self.walker.split_focus()
# move the cursor to the new line and reset pref_col
self.loop.process_input(["down", "home"])
elif k == "right":
w, pos = self.walker.get_focus()
w, pos = self.walker.get_next(pos)
if w:
self.listbox.set_focus(pos, 'above')
self.loop.process_input(["home"])
elif k == "left":
w, pos = self.walker.get_focus()
w, pos = self.walker.get_prev(pos)
if w:
self.listbox.set_focus(pos, 'below')
self.loop.process_input(["end"])
else:
return
return True
def save_file(self):
"""Write the file out to disk."""
l = []
walk = self.walker
for edit in walk.lines:
# collect the text already stored in edit widgets
if edit.original_text.expandtabs() == edit.edit_text:
l.append(edit.original_text)
else:
l.append(re_tab(edit.edit_text))
# then the rest
while walk.file is not None:
l.append(walk.read_next_line())
# write back to disk
outfile = open(self.save_name, "w")
prefix = ""
for line in l:
outfile.write(prefix + line)
prefix = "\n"
def re_tab(s):
"""Return a tabbed string from an expanded one."""
l = []
p = 0
for i in range(8, len(s), 8):
if s[i-2:i] == " ":
# collapse two or more spaces into a tab
l.append(s[p:i].rstrip() + "\t")
p = i
if p == 0:
return s
else:
l.append(s[p:])
return "".join(l)
def main():
try:
name = sys.argv[1]
assert open(name, "a")
except:
sys.stderr.write(__doc__)
return
EditDisplay(name).main()
if __name__=="__main__":
main()
在这里检查: http://urwid.org/reference/widget.html#urwid.Frame
有更新插件功能吗?