就像 TheLizzard 所说的,这对于 Text 小部件的内置撤消/重做机制是不可能的。但是,您可以实现自己的撤消/重做机制来处理格式化。
这个想法是有一个撤消堆栈和一个重做堆栈。我对两者都使用了列表。当您调用撤消函数时,您将撤消堆栈中的最后一项,将其附加到重做堆栈并使用该项中的信息来撤消修改。它通常是一个(undo_args, redo_args) 元组。然后对于重做功能,您执行相同的操作,只是从重做堆栈中取出项目并将其附加到撤消堆栈。
但是,您需要在每次修改发生时将所需的(undo_args, redo_args) 附加到撤消堆栈,并清除重做堆栈。
为此,我改编了 Brayn Oakley 的回答 https://stackoverflow.com/a/16375233/6415268 中的代理机制(关于自动更新行号)。
每次修改Text 小部件时,都会调用_proxy 方法。如果此修改是文本插入、文本删除、标记添加或标记删除,则 (undo_args, redo_args) 元组将附加到撤消堆栈。因此可以通过调用self.tk.call((self._orig,) + undo_args) 撤消修改并使用self.tk.call((self._orig,) + redo_args) 重做。
import tkinter as tk
class MyText(tk.Text):
def __init__(self, master=None, **kw):
tk.Text.__init__(self, master, undo=False, **kw)
self._undo_stack = []
self._redo_stack = []
# create proxy
self._orig = self._w + "_orig"
self.tk.call("rename", self._w, self._orig)
self.tk.createcommand(self._w, self._proxy)
def _proxy(self, *args):
if args[0] in ["insert", "delete"]:
if args[1] == "end":
index = self.index("end-1c")
else:
index = self.index(args[1])
if args[0] == "insert":
undo_args = ("delete", index, "{}+{}c".format(index, len(args[2])))
else: # args[0] == "delete":
undo_args = ("insert", index, self.get(*args[:1]))
self._redo_stack.clear()
self._undo_stack.append((undo_args, args))
elif args[0] == "tag":
if args[1] in ["add", "remove"] and args[2] != "sel":
indexes = tuple(self.index(ind) for ind in args[3:])
undo_args = ("tag", "remove" if args[1] == "add" else "add", args[2]) + indexes
self._redo_stack.clear()
self._undo_stack.append((undo_args, args))
result = self.tk.call((self._orig,) + args)
return result
def undo(self):
if not self._undo_stack:
return
undo_args, redo_args = self._undo_stack.pop()
self._redo_stack.append((undo_args, redo_args))
self.tk.call((self._orig,) + undo_args)
def redo(self):
if not self._redo_stack:
return
undo_args, redo_args = self._redo_stack.pop()
self._undo_stack.append((undo_args, redo_args))
self.tk.call((self._orig,) + redo_args)
root = tk.Tk()
text = MyText(root, width=65, height=20, font="consolas 14")
text.pack()
undo_button = tk.Button(root, text="Undo", command=text.undo)
undo_button.pack()
redo_button = tk.Button(root, text="Redo", command=text.redo)
redo_button.pack()
text.insert('end', "Hello world")
text.tag_add('test', '1.0', '1.5')
text.tag_config('test', background='yellow')
root.mainloop()