Отменить и повторить в виджете входа Tkinter? - PullRequest
4 голосов
/ 10 ноября 2010

Есть ли способ добавить отменить и повторить возможности в виджетах Tkinter Entry или я должен использовать однострочные Text виджеты для этого типа функциональности?

Если последнее, есть ли какие-либо советы, которым я должен следовать при настройке виджета Text для работы в качестве виджета Entry?

Некоторые функции, которые могут нуждаться в настройке, включают перехват Return KeyPress, преобразование нажатий клавиш табуляции в запрос на изменение фокуса и удаление новых строк из текста, вставляемого из буфера обмена.

Ответы [ 3 ]

2 голосов
/ 10 ноября 2010

Отказ от ответственности: это просто мысли, которые приходят мне в голову о том, как его реализовать.

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)

Остерегайтесь установкиблокируется при необходимости.

1 голос
/ 11 апреля 2016

Проверьте пользовательский ввод 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
1 голос
/ 03 сентября 2015

Обновление при использовании этого метода для отмены / повторения:

Я создаю графический интерфейс с большим количеством кадров, и каждый из них содержит не менее десяти или более виджетов 'entry'.Я использовал класс History и создал один объект истории для каждого поля ввода, которое у меня было.Я был в состоянии сохранить все значения входных виджетов в списке, как здесь.Я использую метод «trace», прикрепленный к каждому виджету записи, который будет вызывать функцию «add» класса History и сохранять все изменения.Таким образом, я смог сделать это без отдельного запуска какого-либо потока.Но самым большим недостатком этого является то, что мы не можем делать несколько отмен / повторов с помощью этого метода.

Проблема: Когда я отслеживаю каждое изменение виджета ввода и добавляю его в список, он также 'отслеживает«изменение, которое происходит, когда мы« отменяем / возвращаем », что означает, что мы не можем сделать больше шага назад.как только вы сделаете отмену, это изменение, которое будет отслежено, и, следовательно, значение 'отменить' будет добавлено в список в конце.Следовательно, это не правильный метод.

Решение: Идеальный способ сделать это - создать два стека для каждого виджета ввода.Один для «Отменить» и один для «Повторить».Если когда-либо произойдет изменение записи, поместите это значение в стек отмены.Когда пользователь нажимает «Отменить», извлеките последнее сохраненное значение из стека отмены и, что важно, поместите его в «стек повторного выполнения».следовательно, когда пользователь нажимает redo, извлекает последнее значение из стека redo.

...