python tkinter infinite loop freezes

Viewed 46

im currently making a tkinter app that auto backup files by watching the last mod time of the file. code is as below.

from tkinter import *
from tkinter import filedialog
import shutil
import os
from datetime import datetime

app = Tk()
app.title("7dtd auto backup")
app.geometry("800x500")
stopsign = False


def stop():
    global stopsign
    stopsign = True

def getSrcFolderPath():
    folder_selected = filedialog.askopenfilename()
    src_text.set(folder_selected)

def getDstFolderPath():
    folder_selected = filedialog.askdirectory()
    dst_text.set(folder_selected)

def watchpath(file, folder):
    global stopsign
    file = file.get()
    folder = folder.get()
    backupnum = 1
    if file != "":
        lastmtime = os.path.getmtime(file)
        while stopsign == False:
            if os.path.getmtime(file) != lastmtime:
                lastmtime = os.path.getmtime(file)
                shutil.copytree(os.path.dirname(file), folder+"/backup"+str(backupnum))
                backupnum += 1

src_text = StringVar() #source file selector
src_label = Label(app, text="save file")
src_label.grid(row=0, column=0)
src_entry = Entry(app, textvariable=src_text)
src_entry.grid(row=0, column=1)
src_btn = Button(app, text="browse", width=12, command=lambda: getSrcFolderPath())
src_btn.grid(row=0, column=2)

dst_text = StringVar()
dst_label = Label(app, text="destination folder")
dst_label.grid(row=0, column=3)
dst_entry = Entry(app, textvariable=dst_text)
dst_entry.grid(row=0, column=4)
dst_btn = Button(app, text="browse", width=12, command=lambda: getDstFolderPath())
dst_btn.grid(row=0, column=5)

start_btn = Button(app, text="start", width=12, command=lambda: watchpath(src_text, dst_text))
start_btn.grid(row=2, column=0)
end_btn = Button(app, text="end", width=12, command=lambda: stop())
end_btn.grid(row=2, column=1)

app.mainloop()

the idea is that im setting an infinite loop for the function to keep fetching the last mod time of the file until it has changed, but doing so will make my app freeze during the loop, which means that the app can only be stopped by closing. Is there a way to make it not freeze while still maintaining the function of detecting the change in last mod time? Much appreciated!

1 Answers

The tkinter package offers a widget.after() function that allows you to call a function of your choice after a delay of X milliseconds. It's signature is as follows: w.after(delay_ms, callback=None, *args_for_your_function)

To make your code work, you can declare lastmtime as a global variable at the start of your code and then change your watchpatch function to the following:

def watchpath(fileVar, folderVar):
    print("watchpatch firing...")
    global stopsign
    global lastmtime
    if stopsign:
        stopsign = False
        print("Stopping watchpath!")
        return
    file = fileVar.get()
    folder = folderVar.get()
    backupnum = 1
    if file != "" and os.path.getmtime(file) != lastmtime:
        lastmtime = os.path.getmtime(file)
        while os.path.exists(folder+"/backup"+str(backupnum)):
            backupnum += 1
        print("Copying folder contents to backup folder...")
        shutil.copytree(os.path.dirname(file), folder+"/backup"+str(backupnum))
        backupnum += 1
    app.after(1000, watchpath, fileVar, folderVar)

Points to note:

  • Your program actually seems to copy the entire contents of the srcfile directory to the specified backup directory, not just the individual file. I've left this logic as-is, but you might want to change it if your goal is to backup just the one file.
  • I added in some basic print statements to help you understand what's happening. Remove these once you're good to go.
Related