Thanks for stopping by at my post; as amateur python writer, I'm writing a code to schedule a Copy & Paste process based on time previously defined by a user.
There should be 3 different times in the day where the copy & paste process should be executed. When I run the process independently it works just fine, however, when I try to run two or moew the error I'm having is that the Progress creates a secondary window causing the code fail trying to close two windows, the actual progress bar and the "parasite" progress bar.
When I run only one process only pop-up one single progress bar pop-up once and close without no issues.
However, when I run two process simultaneously, at the time schedule one executed opens two progress bar however when Tkinter try to close it the two bars it shows an error. please see below my code:
import tkinter as tkfrom tkinter import ttkfrom tkinter import filedialogfrom tkinter import messageboximport shutilfrom threading import Thread import osfrom datetime import datetimeimport schedule, timefrom tkinter import simpledialogclass FileCopyGUI: def __init__(self, master): global time_str_one, time_str_two, time_str_three time_str_one="";time_str_two="";time_str_three="" self.password_unlock = "h" self.password_stop = "o" self.master = master self.master.title("Simple - PreParser Tool v1.00") self.master.iconbitmap("simple.ico") self.master.resizable(False,False) def update_time(): current_time = datetime.now().strftime("%I:%M:%S %p") current_date = datetime.now().strftime("%d %b, %Y") self.datetime_label = tk.Label(text=("Date & Time "), font=("Tahoma", 11)) self.datetime_label.grid(row=0, column=0, sticky=tk.W, padx=5, pady=5) self.datetime_label = tk.Label(text=("" + current_date +", " + current_time), font=("Tahoma", 11)) self.datetime_label.grid(row=0, column=1, sticky=tk.W, padx=5, pady=5) self.master.after(1000, update_time) # Update every 1 second update_time() self.source_label = tk.Label(master, text="Source ", font=("Tahoma", 11), state=tk.DISABLED) self.source_label.grid(row=1, column=0, sticky=tk.W, padx=5, pady=5) self.source_entry = tk.Entry(master, width=50, font=("Tahoma", 11), state=tk.DISABLED) self.source_entry.grid(row=1, column=1, sticky=tk.W, padx=5, pady=5) self.source_button = tk.Button(master, text=" Browse Folder ", font=("Tahoma", 11), command=self.browse_source, state=tk.DISABLED) self.source_button.grid(row=1, column=2, sticky=tk.W, padx=5, pady=5) self.destination_label = tk.Label(master, text="Destination ", font=("Tahoma", 11), state=tk.DISABLED) self.destination_label.grid(row=2, column=0, sticky=tk.W, padx=5, pady=5) self.destination_entry = tk.Entry(master, width=50, font=("Tahoma", 11), state=tk.DISABLED) self.destination_entry.grid(row=2, column=1, sticky=tk.W, padx=5, pady=5) self.destination_button = tk.Button(master, text=" Browse Folder ", font=("Tahoma", 11), command=self.browse_destination, state=tk.DISABLED) self.destination_button.grid(row=2, column=2, sticky=tk.W, padx=5, pady=5) self.schedule_one = ttk.Label(master, text="Enter time schedule 1 ", font=("Tahoma", 11), state=tk.DISABLED) self.schedule_one.grid(row=3, column=0, sticky=tk.W, padx=5, pady=5) self.time_entry_one = tk.Entry(master, width=10, font=("Tahoma", 11), state=tk.DISABLED) self.time_entry_one.grid(row=3, column=1, sticky=tk.W, padx=5, pady=5) self.schedule_button_one = tk.Button(master, text=" Schedule ", font=("Tahoma", 11), command=self.schedule_1, state=tk.DISABLED) self.schedule_button_one.grid(row=3, column=2, sticky=tk.W, padx=5, pady=5) self.schedule_two = ttk.Label(master, text="Enter time schedule 2 ", font=("Tahoma", 11), state=tk.DISABLED) self.schedule_two.grid(row=4, column=0, sticky=tk.W, padx=5, pady=5) self.time_entry_two = tk.Entry(master, width=10, font=("Tahoma", 11), state=tk.DISABLED) self.time_entry_two.grid(row=4, column=1, sticky=tk.W, padx=5, pady=5) self.schedule_button_two = tk.Button(master, text=" Schedule ", font=("Tahoma", 11), command=self.schedule_2, state=tk.DISABLED) self.schedule_button_two.grid(row=4, column=2, sticky=tk.W, padx=5, pady=5) self.schedule_three = ttk.Label(master, text="Enter time schedule 3 ", font=("Tahoma", 11), state=tk.DISABLED) self.schedule_three.grid(row=5, column=0, sticky=tk.W, padx=5, pady=5) self.time_entry_three = tk.Entry(master, width=10, font=("Tahoma", 11), state=tk.DISABLED) self.time_entry_three.grid(row=5, column=1, sticky=tk.W, padx=5, pady=5) self.schedule_button_three = tk.Button(master, text=" Schedule ", font=("Tahoma", 11), command=self.schedule_3, state=tk.DISABLED) self.schedule_button_three.grid(row=5, column=2, sticky=tk.W, padx=5, pady=5) self.unlock_button = tk.Button(master, text=" Locked... ", command=self.check_password, font=("Tahoma", 11)) self.unlock_button.grid(row=10, column=1, sticky=tk.W, padx=0, pady=5) self.run_button = tk.Button(master, text=" RUN ", font=("Tahoma", 11), command=self.copy_files, state=tk.DISABLED) self.run_button.grid(row=10, column=1, sticky=tk.W, padx=160, pady=0) self.stop_button = tk.Button(master, text=" STOP ", font=("Tahoma", 11), command=self.clear_gui, state=tk.DISABLED) self.stop_button.grid(row=10, column=1, sticky=tk.W, padx=315, pady=5) self.simple_label = tk.Label(master, text="Simple ", font=("Tahoma", 8)) self.simple_label.grid(row=11, column=0, sticky=tk.W, padx=0, pady=0) self.simple_label = tk.Label(master, text="Engineering Services ", font=("Tahoma", 8)) self.simple_label.grid(row=12, column=0, sticky=tk.W, padx=0, pady=0) self.simple_label = tk.Label(master, text=" Simple ", font=("Tahoma", 8, "italic", "bold"), fg="blue" ) self.simple_label.grid(row=13, column=0, sticky=tk.W, padx=0, pady=0) self.simple_label = tk.Label(master, text="www.s.com.mx ", font=("Tahoma", 8)) self.simple_label.grid(row=14, column=0, sticky=tk.W, padx=0, pady=0) def check_password(self): entered_password = tk.simpledialog.askstring("Simple - PreParser Tool v1.00", "Enter Password", show='*') if entered_password == self.password_unlock: messagebox.showinfo("Simple - PreParser Tool v1.00", " Access Granted...! ") self.unlock_button = tk.Button(text=" Unlocked... ", font=("Tahoma", 11)) self.unlock_button.grid(row=10, column=1, sticky=tk.W, padx=0, pady=5) self.unlock_button.config(state=tk.DISABLED) self.source_label.config(state=tk.NORMAL) self.source_entry.config(state=tk.NORMAL) self.source_button.config(state=tk.NORMAL) self.destination_label.config(state=tk.NORMAL) self.destination_entry.config(state=tk.NORMAL) self.destination_button.config(state=tk.NORMAL) else: messagebox.showerror("Simple - PreParser Tool v1.00", "Incorrect Password...! Please try again") return def browse_source(self): global source_folder source_folder = filedialog.askdirectory() if source_folder: self.source_entry.delete(0, tk.END) self.source_entry.insert(0, source_folder) def browse_destination(self): global destination_folder destination_folder = filedialog.askdirectory() if destination_folder: self.destination_entry.delete(0, tk.END) self.destination_entry.insert(0, destination_folder) if (destination_folder) != "" and (source_folder) != "": self.schedule_one.config(state=tk.NORMAL) self.time_entry_one.config(state=tk.NORMAL) self.schedule_button_one.config(state=tk.NORMAL) self.schedule_two.config(state=tk.NORMAL) self.time_entry_two.config(state=tk.NORMAL) self.schedule_button_two.config(state=tk.NORMAL) self.schedule_three.config(state=tk.NORMAL) self.time_entry_three.config(state=tk.NORMAL) self.schedule_button_three.config(state=tk.NORMAL) def schedule_1(self): global time_str_one, time_str_two, time_str_three time_str_one = self.time_entry_one.get() import re if re.match(r'^([01]?[0-9]|2[0-3]):[0-5][0-9]$', time_str_one): tk.messagebox.showinfo("Simple - PreParser Tool v1.00", "Task has been properly scheduled to be executed") self.schedule_one.config(state=tk.DISABLED) self.time_entry_one.config(state=tk.DISABLED) self.schedule_button_one.config(state=tk.DISABLED) self.run_button.config(state=tk.NORMAL) self.stop_button.config(state=tk.NORMAL) else: tk.messagebox.showerror("Simple - PreParser Tool v1.00", "Invalid time format. Please enter time in 12-hour HH:MM AM/PM format.") return def schedule_2(self): global time_str_one, time_str_two, time_str_three time_str_two = self.time_entry_two.get() import re if re.match(r'^([01]?[0-9]|2[0-3]):[0-5][0-9]$', time_str_two): tk.messagebox.showinfo("Simple - PreParser Tool v1.00", "Task has been properly scheduled to be executed") self.schedule_two.config(state=tk.DISABLED) self.time_entry_two.config(state=tk.DISABLED) self.schedule_button_two.config(state=tk.DISABLED) self.run_button.config(state=tk.NORMAL) self.stop_button.config(state=tk.NORMAL) else: tk.messagebox.showerror("Simple - PreParser Tool v1.00", "Invalid time format. Please enter time in 12-hour HH:MM AM/PM format.") return def schedule_3(self): global time_str_one, time_str_two, time_str_three time_str_three = self.time_entry_three.get() import re if re.match(r'^([01]?[0-9]|2[0-3]):[0-5][0-9]$', time_str_three): tk.messagebox.showinfo("Validation", "Task has been properly scheduled to be executed") self.schedule_three.config(state=tk.DISABLED) self.time_entry_three.config(state=tk.DISABLED) self.schedule_button_three.config(state=tk.DISABLED) self.run_button.config(state=tk.NORMAL) self.stop_button.config(state=tk.NORMAL) else: tk.messagebox.showerror("Simple - PreParser Tool v1.00", "Invalid time format. Please enter time in 12-hour HH:MM AM/PM format.") return def copy_files(self): if time_str_one: if time_str_two == "" or time_str_three=="": self.schedule_two.config(state=tk.DISABLED) self.time_entry_two.config(state=tk.DISABLED) self.schedule_button_two.config(state=tk.DISABLED) self.schedule_three.config(state=tk.DISABLED) self.time_entry_three.config(state=tk.DISABLED) self.schedule_button_three.config(state=tk.DISABLED) self.source_label.config(state=tk.DISABLED) self.source_entry.config(state=tk.DISABLED) self.source_button.config(state=tk.DISABLED) self.destination_label.config(state=tk.DISABLED) self.destination_entry.config(state=tk.DISABLED) self.destination_button.config(state=tk.DISABLED) self.run_button.config(state=tk.DISABLED) ##self.master.iconify() def copy_one(): source = self.source_entry.get() destination = self.destination_entry.get() if not os.path.exists(source): messagebox.showerror("PreParser Tool v1.00", "Source directory does not exist.") return if not os.path.exists(destination): messagebox.showerror("PreParser Tool v1.00", "Destination directory does not exist.") return self.progress_window_one = tk.Toplevel(self.master) self.progress_window_one.iconbitmap("simple.ico") self.progress_window_one.title("Copying information per schedule 1...") self.progress_one = ttk.Progressbar(self.progress_window_one, orient="horizontal", length=600, mode="determinate") self.progress_one.grid(row=0, column=0, padx=5, pady=5) total_files = sum(len(files) for _, _, files in os.walk(source)) copied_files = 0 for root, dirs, files in os.walk(source): for file in files: source_file = os.path.join(root, file) destination_file = os.path.join(destination, os.path.relpath(source_file, source)) os.makedirs(os.path.dirname(destination_file), exist_ok=True) shutil.copy2(source_file, destination_file) copied_files += 1 progress_percent_one = int((copied_files / total_files) * 100) self.progress_one["value"] = progress_percent_one self.progress_window_one.update() self.progress_window_one.destroy() def cycle_one(): schedule.every().day.at(time_str_one).do(copy_one) while True: print("cycle 1") schedule.run_pending() time.sleep(1) Thread(target=cycle_one).start() if time_str_two: if time_str_one == "" or time_str_three=="": self.schedule_one.config(state=tk.DISABLED) self.time_entry_one.config(state=tk.DISABLED) self.schedule_button_one.config(state=tk.DISABLED) self.schedule_three.config(state=tk.DISABLED) self.time_entry_three.config(state=tk.DISABLED) self.schedule_button_three.config(state=tk.DISABLED) self.source_label.config(state=tk.DISABLED) self.source_entry.config(state=tk.DISABLED) self.source_button.config(state=tk.DISABLED) self.destination_label.config(state=tk.DISABLED) self.destination_entry.config(state=tk.DISABLED) self.destination_button.config(state=tk.DISABLED) self.run_button.config(state=tk.DISABLED) ##self.master.iconify() def copy_two(): source = self.source_entry.get() destination = self.destination_entry.get() if not os.path.exists(source): messagebox.showerror("Simple - PreParser Tool v1.00", "Source directory does not exist.") return if not os.path.exists(destination): messagebox.showerror("Simple - PreParser Tool v1.00", "Destination directory does not exist.") return self.progress_window_two = tk.Toplevel(self.master) self.progress_window_two.iconbitmap("simple.ico") self.progress_window_two.title("Copying information per schedule 2...") self.progress_two = ttk.Progressbar(self.progress_window_two, orient="horizontal", length=600, mode="determinate") self.progress_two.grid(row=0, column=0, padx=5, pady=5) total_files = sum(len(files) for _, _, files in os.walk(source)) copied_files = 0 for root, dirs, files in os.walk(source): for file in files: source_file = os.path.join(root, file) destination_file = os.path.join(destination, os.path.relpath(source_file, source)) os.makedirs(os.path.dirname(destination_file), exist_ok=True) shutil.copy2(source_file, destination_file) copied_files += 1 progress_percent_two = int((copied_files / total_files) * 100) self.progress_two["value"] = progress_percent_two self.progress_window_two.update() self.progress_window_two.destroy() def cycle_two(): schedule.every().day.at(time_str_two).do(copy_two) while True: print("cycle 2") schedule.run_pending() time.sleep(1) Thread(target=cycle_two).start() if time_str_three: if time_str_one == "" or time_str_two=="": self.schedule_one.config(state=tk.DISABLED) self.time_entry_one.config(state=tk.DISABLED) self.schedule_button_one.config(state=tk.DISABLED) self.schedule_two.config(state=tk.DISABLED) self.time_entry_two.config(state=tk.DISABLED) self.schedule_button_two.config(state=tk.DISABLED) self.source_label.config(state=tk.DISABLED) self.source_entry.config(state=tk.DISABLED) self.source_button.config(state=tk.DISABLED) self.destination_label.config(state=tk.DISABLED) self.destination_entry.config(state=tk.DISABLED) self.destination_button.config(state=tk.DISABLED) self.run_button.config(state=tk.DISABLED) ##self.master.iconify() source = self.source_entry.get() destination = self.destination_entry.get() if not os.path.exists(source): messagebox.showerror("Simple - PreParser Tool v1.00", "Source directory does not exist.") return if not os.path.exists(destination): messagebox.showerror("Simple - PreParser Tool v1.00", "Destination directory does not exist.") return def copy_three(): self.progress_window_three = tk.Toplevel(self.master) self.progress_window_three.iconbitmap("simple.ico") self.progress_window_three.title("Copying information per schedule 3...") self.progress_three = ttk.Progressbar(self.progress_window_three, orient="horizontal", length=600, mode="determinate") self.progress_three.grid(row=0, column=0, padx=5, pady=5) total_files = sum(len(files) for _, _, files in os.walk(source)) copied_files = 0 for root, dirs, files in os.walk(source): for file in files: source_file = os.path.join(root, file) destination_file = os.path.join(destination, os.path.relpath(source_file, source)) os.makedirs(os.path.dirname(destination_file), exist_ok=True) shutil.copy2(source_file, destination_file) copied_files += 1 progress_percent_three = int((copied_files / total_files) * 100) self.progress_three["value"] = progress_percent_three self.progress_window_three.update() self.progress_window_three.destroy() def cycle_three(): schedule.every().day.at(time_str_three).do(copy_three) while True: print("cycle 3") schedule.run_pending() time.sleep(1) Thread(target=cycle_three).start() def clear_gui(self): entered_password = tk.simpledialog.askstring("Simple - PreParser Tool v1.00", "Enter Password", show='*') if entered_password == self.password_stop: exit.set() self.source_entry.delete(0, tk.END) self.destination_entry.delete(0, tk.END) else: messagebox.showerror("Error", "Incorrect password!") returndef main(): root = tk.Tk() app = FileCopyGUI(root) root.mainloop()if __name__ == "__main__": main()