Отменить и повторить в виджете ввода TKinter?
-
30-09-2019 - |
Вопрос
Есть ли способ добавить отменить а также редо Возможности в TKinter. Entry
виджеты или должны использовать одну строку Text
Виджеты для этого типа функциональности?
Если последние, есть ли советы, которые я должен следовать при настройке Text
виджет, чтобы действовать как Entry
Виджет?
Некоторые функции, которые могут нуждаться в настройке, включают в себя ловушку Return
KeyPress
, Преобразование вкладывающих клавиш в запрос на изменение фокусировки и удаление новых линий из текста, вставленного из буфера обмена.
Решение
Отказ от ответственности: Это просто мысли, которые приходят в мой разум о том, как его реализовать.
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)
Остерегайтесь, чтобы установить замки по мере необходимости.
Другие советы
Обновите об использовании этого метода для отмены / REDO:
Я создаю графический интерфейс с большим количеством кадров, и каждый содержит как минимум десять или более виджетов «входа». Я использовал класс истории и создал один объект истории для каждого полевого поля. Я смог хранить все значения въезда в списке, как это сделано здесь. Я использую метод «Trace», прикрепленный к каждому виджету ввода, который позвонит «Добавить» функцию класса истории и хранить каждые изменения. Таким образом, я смог сделать это без каких-либо низов отдельно. Но самый большой недостаток этого делать, мы не можем сделать несколько разбрасываний / Redos с этим методом.
Проблема: когда я отслеживаю каждый и каждый изменение виджета ввода и добавьте это в список, он также «следы» изменения, которые происходят, когда мы «отменить / повторить», что означает, что мы не можем пойти на более одного шага. Как только вы сделаете отменить, это изменение, которое будет прослежено, и, следовательно, «значение« Отменить »будет добавлено в список в конце. Следовательно, это не правильный метод.
Решение: Идеальный способ сделать это - создать два стека для каждого входного виджета. Один для «отменить» и один для «повтора». Когда когда-либо имеется изменение ввода, нажмите это значение в стек отмена. Когда пользователь нажимает Undo, поп-последнее сохраняемое значение из стека «Отменить» и главное нажимайте это на «Stack redo». Следовательно, когда пользователь нажимает Redo, поставьте последнее значение из стека Redo.
Проверьте пользовательскую запись TKinter. Я добавил Cut, Copy, вставьте контекстное меню и отменить функции Redo.
# -*- 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