有没有办法添加撤销和重做功能在Tkinter Entry
部件或必须使用单线Text
小部件这种类型的功能?在Tkinter Entry小部件中撤消和重做?
如果是后者,那么在配置Text
小部件以充当Entry
小部件时,我应该遵循哪些提示?
某些可能需要调整的功能包括捕获Return
KeyPress
,将tab按键转换为改变焦点的请求,以及从剪贴板粘贴的文本中删除换行符。
有没有办法添加撤销和重做功能在Tkinter Entry
部件或必须使用单线Text
小部件这种类型的功能?在Tkinter Entry小部件中撤消和重做?
如果是后者,那么在配置Text
小部件以充当Entry
小部件时,我应该遵循哪些提示?
某些可能需要调整的功能包括捕获Return
KeyPress
,将tab按键转换为改变焦点的请求,以及从剪贴板粘贴的文本中删除换行符。
声明:这些只是我想到的如何实现它的想法。
class History(object):
def __init__(self):
self.l = ['']
self.i = 0
def next(self):
if self.i == len(self.l):
return None
self.i += 1
return self.l[self.i]
def prev(self):
if self.i == 0:
return None
self.i -= 1
return self.l[self.i]
def add(self, s):
del self.l[self.i+1:]
self.l.append(s)
self.i += 1
def current(self):
return self.l[self.i]
运行一个线程,每隔X秒(0.5?)保存条目的状态:
history = History()
...
history.add(stringval.get())
您还可以设置保存条目的状态太事件,如压力Return
。
prev = history.prev()
if prev is not None:
stringvar.set(prev)
或
next = history.next()
if next is not None:
stringvar.set(next)
当心根据需要设置锁。
更新使用此方法撤销/重做:
我创造与很多帧的图形用户界面,并且每个含有至少十个或更多的“进入”小部件。 我使用了History类,并为每个输入字段创建了一个历史对象。我能够将所有的入口小部件值存储在列表中,就像这里所做的那样。 我使用附加到每个条目小部件的'trace'方法,它将调用History类的'add'功能并存储每个更改。通过这种方式,我无需单独运行任何线程即可完成。 但是这样做的最大缺点是,我们无法用这种方法做多个undos/redos。
问题: 当我跟踪条目窗口小部件的每一次更改并将其添加到列表中时,它还'追踪'我们'撤销/重做'时发生的变化,这意味着我们不能再退一步。一旦你做了撤销,这是一个将被追踪的变化,因此'撤消'值将被添加到列表中。因此这不是正确的方法。
解决方案: 完成此操作的最佳方法是为每个条目窗口小部件创建两个堆栈。一个用于'撤销',一个用于'重做'。当条目发生变化时,将该值推入撤消堆栈。当用户按下撤消时,从撤消堆栈中弹出最后存储的值,并且重要地将其推送到“重做堆栈”。因此,当用户按下重做时,从重做堆栈弹出最后一个值。
检查Tkinter自定义条目。我已添加剪切,复制,粘贴上下文菜单,并撤消重做功能。
# -*- coding: utf-8 -*-
from tkinter import *
class CEntry(Entry):
def __init__(self, parent, *args, **kwargs):
Entry.__init__(self, parent, *args, **kwargs)
self.changes = [""]
self.steps = int()
self.context_menu = Menu(self, tearoff=0)
self.context_menu.add_command(label="Cut")
self.context_menu.add_command(label="Copy")
self.context_menu.add_command(label="Paste")
self.bind("<Button-3>", self.popup)
self.bind("<Control-z>", self.undo)
self.bind("<Control-y>", self.redo)
self.bind("<Key>", self.add_changes)
def popup(self, event):
self.context_menu.post(event.x_root, event.y_root)
self.context_menu.entryconfigure("Cut", command=lambda: self.event_generate("<<Cut>>"))
self.context_menu.entryconfigure("Copy", command=lambda: self.event_generate("<<Copy>>"))
self.context_menu.entryconfigure("Paste", command=lambda: self.event_generate("<<Paste>>"))
def undo(self, event=None):
if self.steps != 0:
self.steps -= 1
self.delete(0, END)
self.insert(END, self.changes[self.steps])
def redo(self, event=None):
if self.steps < len(self.changes):
self.delete(0, END)
self.insert(END, self.changes[self.steps])
self.steps += 1
def add_changes(self, event=None):
if self.get() != self.changes[-1]:
self.changes.append(self.get())
self.steps += 1
在这里使用线程是完全没有必要的。小部件可以在更改时轻松通知您。 – 2010-11-10 20:46:00
@Bryan Oakley:不是真的,这只是解决问题的一种不同方法,也是很多解决方案之一。 – 2010-11-11 01:34:59
@MG:良好的计划:捕捉每一个部件的改变,将总值存储在历史列表中,撤消时,将历史指针移回一级并获取其值。重做时,将历史指针向前移动一级并获取其值。存储用户更改时,请在每次更改用户后清除重做历史记录。我不是线程监视的粉丝 - 我需要的是相当于值改变事件(或可能trace_var()),以便我可以跟踪确切的更改。我发布了一个关于这样的事件存在的问题:http://stackoverflow.com/questions/4165164 – Malcolm 2010-11-12 13:48:08