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.
Asked
Active
Viewed 157 times
-2
-
what do you mean by "if the file can be undoable"? Are you asking about whether changes in a text widget are undoable? – Bryan Oakley Dec 31 '19 at 17:44
-
yes that's my purpose – B4ST14 Dec 31 '19 at 17:51
1 Answers
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
-
-
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