Я пишу программу для копирования файлов из одного места в другое. Чтобы ускорить процесс, я использовал processpoolexecutor и отправил задания, используя shutil.copy2 для копирования файлов. Моя программа имеет графический интерфейс, и когда я запускаю ее, открывается несколько окон графического интерфейса.
Есть ли способ предотвратить это?
file 1
import Copy_file
import tkinter as tk
from tkinter import filedialog
from tkinter import ttk
from PIL import ImageTk, Image
import threading
# setup window
window = tk.Tk()
window.title("Simple File Backup")
window.resizable(False, False)
window.iconbitmap("Images\\Icon.ico")
class main_window:
def __init__(self, root):
# create global variable
self.source_dialog_selected_directory = tk.StringVar()
self.destination_dialog_selected_directory = tk.StringVar()
# initialise other program
self.copy = Copy_file.copy_file()
# configure styles
self.s = ttk.Style()
self.s.configure("TButton", font=("Humanst521 BT", 15))
self.s.configure("main.TLabel", font=("Humanst521 BT", 10))
self.s.configure("title.TLabel", font=("Humanst521 BT", 19))
self.s.configure("browse.TButton", font=("Humanst521_BT", 8))
# create frames
self.main_frame = ttk.Frame(root, padding=10)
self.main_frame.grid()
self.top_frame = ttk.Frame(self.main_frame)
self.top_frame.grid(row=0)
self.extra_frame = ttk.Frame(self.main_frame)
self.extra_frame.grid(row=1)
# add logo
self.logo = Image.open("Images\\Icon.png")
self.logo = self.logo.resize((50, 50), Image.ANTIALIAS)
self.logo = ImageTk.PhotoImage(self.logo)
self.show_logo = tk.Label(self.top_frame, image=self.logo, relief="sunken")
self.show_logo.image = self.logo
self.show_logo.grid(row=0, column=1, columnspan=2, sticky="e", pady=3)
# title
ttk.Label(self.top_frame, text="Simple File Backup", style="title.TLabel").grid(row=0, column=0, columnspan=2)
# create main layout
ttk.Label(self.top_frame, text="Source Directory: ", style="main.TLabel").grid(row=1, column=0, pady=3)
self.source_directory = ttk.Entry(self.top_frame, width=30,
textvariable=(self.source_dialog_selected_directory if not self.source_dialog_selected_directory == "" else None))
self.source_directory.grid(row=1, column=1, pady=1)
ttk.Label(self.top_frame, text="Destination Directory: ", style="main.TLabel").grid(row=2, column=0, pady=3)
self.destination_directory = ttk.Entry(self.top_frame, width=30,
textvariable=(self.destination_dialog_selected_directory if not self.destination_dialog_selected_directory == "" else None))
self.destination_directory.grid(row=2, column=1, pady=3)
# open file explorer buttons
self.source_browse = ttk.Button(self.top_frame, text="---", width=4, style="browse.TButton",
command=lambda:self.source_dialog())
self.source_browse.grid(row=1, column=2, sticky="ns", padx=2)
self.destination_browse = ttk.Button(self.top_frame, text="---", width=4, style="browse.TButton",
command=lambda:self.destination_dialog())
self.destination_browse.grid(row=2, column=2, sticky="ns", padx=2)
# copy button
self.copy_button = ttk.Button(self.top_frame, text="Copy", style="TButton", command=lambda:self.start())
self.copy_button.grid(row=3, column=0, columnspan=3, pady=5)
# extra items layout
self.progress_bar = ttk.Progressbar(self.extra_frame, orient="horizontal", length=350, value=0)
self.progress_bar.pack(side="top")
self.output_box = tk.Text(self.extra_frame, takefocus=0, width=50, height=15, font=("Humanst521_BT", 10))
self.output_box.pack(side="left", pady=5, padx=5)#, sticky="nsew")
self.scrollbar = ttk.Scrollbar(self.extra_frame)
self.scrollbar.pack(fill="y", side="right")
self.scrollbar.config(command=self.output_box.yview)
self.output_box.config(yscrollcommand=self.scrollbar.set)
def start(self):
self.reset_progressbar()
self.update_progressbar()
self.reset_output()
copy_thread = threading.Thread(target=self.copy.main_copy, args=(self.get_contents(self.source_directory),
self.get_contents(self.destination_directory)))
copy_thread.start()
output_thread = threading.Thread(target=self.update_output, args=())
output_thread.start()
def reset_output(self):
self.output_box.delete(1.0, tk.END)
def update_output(self):
self.output_box_split = ""
while self.copy.finished == False:
if not self.copy.output == "":
self.output_box.insert(tk.END, self.copy.output)
self.output_box.insert(tk.END, "---------------------\n")
self.copy.output = ""
def reset_progressbar(self):
self.progress_bar["value"] = 0
def update_progressbar(self):
if not self.progress_bar["value"] == 100.0:
self.progress_bar["value"] = self.copy.current_progress()
print(self.copy.current_progress())
window.after(500, self.update_progressbar)
def source_dialog(self):
self.source_dialog_selected_directory.set(filedialog.askdirectory(title="Select source directory"))
print(self.source_dialog_selected_directory.get())
def destination_dialog(self):
self.destination_dialog_selected_directory.set(filedialog.askdirectory(title="Select destination directory"))
print(self.destination_dialog_selected_directory.get())
def get_contents(self, object):
self.output = object.get()
return self.output
# run main_window class with root at tkinter window
main_window(window)
# main gui loop
tk.mainloop()
file2, называется Copy_file.py. Проблема в функции copy ()
import os, shutil, threading
from time import sleep
from concurrent.futures import ProcessPoolExecutor
class copy_file():
def __init__(self):
self.file_bytes_copied = 0
self.full_directory_size = 0
self.output = ""
self.finished = False
self.jobs = {}
def get_directory_size(self, directory):
total_size = 0
for dir, subdir, file in os.walk(directory):
for x in range(len(file)):
total_size += os.stat(dir + "\\" + file[x]).st_size
return total_size
def current_progress(self):
if self.file_bytes_copied > 0 and self.full_directory_size > 0:
progress = (self.file_bytes_copied/self.full_directory_size)*100
progress = round(progress, 2)
return progress
def concatenate_file_modification(self, path):
name = os.path.basename(path)
name = name.split(".")
mod_time = str(os.stat(path).st_mtime)
mod_time = mod_time.replace(".", "-")
concatenate = name[0]+" "+mod_time+"."+name[1]
return concatenate
def copy(self):
with ProcessPoolExecutor(max_workers=3) as executor:
for src, dst in self.jobs.items():
self.output = src + " wasn't found in destination, creating copy...\n"
sleep(0.001)
executor.submit(shutil.copy2, src, dst)
def main_copy(self, source, destination):
self.finished = False
self.file_bytes_copied = 0
self.full_directory_size = self.get_directory_size(source)
self.file_bytes_copied = 0.01
for self.root_dir, self.sub_dir, self.file in os.walk(source):
# remove the first part of the source, leaving the relative directory of the files within the source
self.root_dir = self.root_dir[len(source):]
# create current directory variable
self.current_directory = destination+self.root_dir
# iterate through sub-directories
for y in range(len(self.sub_dir)):
# check if directory exists, if not create it
if not os.path.isdir(self.current_directory+"\\"+self.sub_dir[y]):
self.output = self.current_directory+"\\"+self.sub_dir[y] + " wasn't found in destination, creating...\n"
os.mkdir(self.current_directory+"\\"+self.sub_dir[y])
sleep(0.001)
else:
self.output = self.current_directory + "\\" + self.sub_dir[y] + " was found in destination, no action taken\n"
sleep(0.001)
# iterate through files
for self.i in range(len(self.file)):
# get the file directory to search for
self.file_to_search = self.current_directory+"\\"+self.concatenate_file_modification(source+self.root_dir+"\\"+self.file[self.i])
# check if path exists, if not copy across file
if not os.path.exists(self.file_to_search):
self.jobs[source + self.root_dir + "\\" + self.file[self.i]] = self.file_to_search
# if file does exist, print no action taken
elif os.path.exists(self.file_to_search):
self.output = self.file_to_search + " was found in destination, no action taken\n"
sleep(0.001)
# update file_bytes_copied to current progress
self.file_bytes_copied += os.stat(source + self.root_dir + "\\" + self.file[self.i]).st_size
self.copy()
#print(self.jobs)
self.finished = True