-2

I want to create an undo button that changes its state to disabled when it can't undo. I only want to know if there is a function that knows if the file is undoable or not.

Andronicus
  • 25,419
  • 17
  • 47
  • 88
B4ST14
  • 33
  • 7

1 Answers1

0

This is a very basic prototype which should demonstrate an undo button:

import tkinter as tk

undo_history = []
n = 0

def undo_action():
    x = undo_history.pop()
    if len(undo_history) == 0:
        undoBtn.config(state=tk.DISABLED)

    print("Un-did this:", x)

def do_action():
    global n
    n += 1
    undo_history.append(f"Action {n}")
    if len(undo_history) == 1:
        undoBtn.config(state=tk.NORMAL)

    print("Did this:", undo_history[-1])


root = tk.Tk()

undoBtn   = tk.Button(root, text="Undo", command=undo_action)
actionBtn = tk.Button(root, text="Do something!", command=do_action)

undoBtn.pack()
actionBtn.pack()

root.mainloop()

In terms of applying this to a file, you could read the file, and record its contents every few seconds. If they have changed, you record it as a new state in do_action. In undo_action, you can then write the change to the file.

An example of this is below:

import tkinter as tk, time, threading

filename = "test.txt"

undo_history = []

with open(filename) as f:
    prev_state = f.read()
orig_state = prev_state

undo = False
def undo_action():
    global undo, prev_state
    undo = True

    x = undo_history.pop()
    if len(undo_history) == 0:
        undoBtn.config(state=tk.DISABLED) # disable btn

    if len(undo_history) > 0:
        state = undo_history[-1]
    else:
        state = orig_state

    prev_state = state
    open(filename, 'w').write(state)

    print("Un-did this:", x)
    print("New State:", state)

    undo = False

def check_action():
    global prev_state

    while undo: # undo_action is running
        continue

    with open(filename) as f:
        state = f.read()

    if state == prev_state:
        return

    prev_state = state

    undo_history.append(state)
    undoBtn.config(state=tk.NORMAL)

    print("State:", state)

def run_checks():
    while True: # check for changes every 0.5 secs
        check_action()
        time.sleep(0.5)

root = tk.Tk()

undoBtn = tk.Button(root, text="Undo", command=undo_action)
undoBtn.config(state=tk.DISABLED)
undoBtn.pack()

t = threading.Thread(target=run_checks)
t.start()

root.mainloop()

This code runs automatic checks on the content of the file every 0.5 secs, and allows you to undo those changes. Hopefully this works for you.

Ed Ward
  • 2,333
  • 2
  • 10
  • 16
  • I've got one error in your second script FileNotFoundError: [Errno 2] No such file or directory: 'test.txt', but I've created test.txt file in the same directory as the python file. What type of path I have to use? – B4ST14 Dec 31 '19 at 12:32
  • try using an absolute path, eg r"C:\path\to\your\file\test.txt" on Windows, or "/path/to/your/file/test.txt" on Mac/Unix – Ed Ward Dec 31 '19 at 12:39
  • I've used absolute path and it give me an error: x = undo_history.pop() IndexError: pop from empty list – B4ST14 Dec 31 '19 at 17:17
  • Sorry, I need to make the button disabled by default. – Ed Ward Dec 31 '19 at 17:20
  • why downvote? The code runs perfectly fine on my machine, and it demonstrates the concept of an undo button in a tkinter window. – Ed Ward Jan 01 '20 at 11:03