缘由:
朋友有一个这样的需求,有三个文件夹,文件夹A内含有很多txt文件,文件夹B中也内含有很多txt文件,文件夹C中还是含有很多txt文件。需要把txt文件复制到同个文件夹中
功能:
选择目录将目录下多个文件夹内的文件复制到一个文件夹中
运行图:
下载地址:
包含打包好的成品和源代码。
python打包使用的是Pyinstaller打包。
链接:https://ide.lanzouv.com/b0foqio5i
密码:ao4j
更新:
2024.08.27 v1.1.0
1.增加线程防止界面复制时候处于 未响应 状态
2.增加进度条显示
2024.08.27 v1.0.0
初始版本
源代码:
一共有4个文件:main.py、ui.py、control.py、logo.ico
main.py
# 导入布局文件
from ui import Win as MainWin
# 导入窗口控制器
from control import Controller as MainUIController
# 将窗口控制器 传递给UI
app = MainWin(MainUIController())
if __name__ == "__main__":
# 启动
app.mainloop()
ui.py
from tkinter import *
from tkinter.ttk import *
class WinGUI(Tk):
def __init__(self):
super().__init__()
self.__win()
self.tk_label_m0c6l6hz = self.__tk_label_m0c6l6hz(self)
self.tk_input_m0c6lpcn = self.__tk_input_m0c6lpcn(self)
self.tk_button_m0c6lvy7 = self.__tk_button_m0c6lvy7(self)
self.tk_label_m0c6mm3a = self.__tk_label_m0c6mm3a(self)
self.tk_input_m0c6n6vi = self.__tk_input_m0c6n6vi(self)
self.tk_button_m0c6nb3j = self.__tk_button_m0c6nb3j(self)
self.tk_button_m0c7djh2 = self.__tk_button_m0c7djh2(self)
self.tk_progressbar_m0d8ueyu = self.__tk_progressbar_m0d8ueyu(self)
self.tk_label_m0d8xhee = self.__tk_label_m0d8xhee(self)
self.tk_label_m0dhb051 = self.__tk_label_m0dhb051(self)
def __win(self):
self.title("多个文件夹内的文件复制到一个文件夹中_v1.1.0")
# 设置窗口大小、居中
width = 572
height = 263
screenwidth = self.winfo_screenwidth()
screenheight = self.winfo_screenheight()
geometry = '%dx%d+%d+%d' % (width, height, (screenwidth - width) / 2, (screenheight - height) / 2)
self.geometry(geometry)
self.resizable(width=False, height=False)
def scrollbar_autohide(self, vbar, hbar, widget):
"""自动隐藏滚动条"""
def show():
if vbar: vbar.lift(widget)
if hbar: hbar.lift(widget)
def hide():
if vbar: vbar.lower(widget)
if hbar: hbar.lower(widget)
hide()
widget.bind("<Enter>", lambda e: show())
if vbar: vbar.bind("<Enter>", lambda e: show())
if vbar: vbar.bind("<Leave>", lambda e: hide())
if hbar: hbar.bind("<Enter>", lambda e: show())
if hbar: hbar.bind("<Leave>", lambda e: hide())
widget.bind("<Leave>", lambda e: hide())
def v_scrollbar(self, vbar, widget, x, y, w, h, pw, ph):
widget.configure(yscrollcommand=vbar.set)
vbar.config(command=widget.yview)
vbar.place(relx=(w + x) / pw, rely=y / ph, relheight=h / ph, anchor='ne')
def h_scrollbar(self, hbar, widget, x, y, w, h, pw, ph):
widget.configure(xscrollcommand=hbar.set)
hbar.config(command=widget.xview)
hbar.place(relx=x / pw, rely=(y + h) / ph, relwidth=w / pw, anchor='sw')
def create_bar(self, master, widget, is_vbar, is_hbar, x, y, w, h, pw, ph):
vbar, hbar = None, None
if is_vbar:
vbar = Scrollbar(master)
self.v_scrollbar(vbar, widget, x, y, w, h, pw, ph)
if is_hbar:
hbar = Scrollbar(master, orient="horizontal")
self.h_scrollbar(hbar, widget, x, y, w, h, pw, ph)
self.scrollbar_autohide(vbar, hbar, widget)
def __tk_label_m0c6l6hz(self, parent):
label = Label(parent, text="需要复制的文件夹:", anchor="center", )
label.place(x=14, y=8, width=116, height=30)
return label
def __tk_input_m0c6lpcn(self, parent):
ipt = Entry(parent, )
ipt.place(x=14, y=40, width=454, height=30)
return ipt
def __tk_button_m0c6lvy7(self, parent):
btn = Button(parent, text="选择路径", takefocus=False, )
btn.place(x=486, y=40, width=73, height=30)
return btn
def __tk_label_m0c6mm3a(self, parent):
label = Label(parent, text="保存的路径:", anchor="center", )
label.place(x=14, y=80, width=81, height=30)
return label
def __tk_input_m0c6n6vi(self, parent):
ipt = Entry(parent, )
ipt.place(x=14, y=112, width=454, height=30)
return ipt
def __tk_button_m0c6nb3j(self, parent):
btn = Button(parent, text="选择路径", takefocus=False, )
btn.place(x=485, y=112, width=73, height=30)
return btn
def __tk_button_m0c7djh2(self, parent):
btn = Button(parent, text="开始复制", takefocus=False, )
btn.place(x=302, y=178, width=224, height=71)
return btn
def __tk_progressbar_m0d8ueyu(self, parent):
progressbar = Progressbar(parent, orient=HORIZONTAL, )
progressbar.place(x=14, y=184, width=195, height=30)
return progressbar
def __tk_label_m0d8xhee(self, parent):
label = Label(parent, text="复制进度:", anchor="center", )
label.place(x=14, y=152, width=57, height=30)
return label
def __tk_label_m0dhb051(self, parent):
label = Label(parent, text="", anchor="center", )
label.place(x=14, y=221, width=219, height=30)
return label
class Win(WinGUI):
def __init__(self, controller):
self.ctl = controller
super().__init__()
self.__event_bind()
self.__style_config()
self.ctl.init(self)
def __event_bind(self):
self.tk_button_m0c6lvy7.bind('<Button-1>', self.ctl.choosePatha)
self.tk_button_m0c6nb3j.bind('<Button-1>', self.ctl.choosePathb)
self.tk_button_m0c7djh2.bind('<Button-1>', self.ctl.startCopy)
pass
def __style_config(self):
pass
if __name__ == "__main__":
win = WinGUI()
win.mainloop()
control.py
import threading
import os
import shutil
import tkinter as tk
from tkinter import filedialog
from tkinter.messagebox import showinfo
class Controller:
# 导入UI类后,替换以下的 object 类型,将获得 IDE 属性提示功能
ui: object
def __init__(self):
self.monitor_running = None
def init(self, ui):
self.ui = ui
# TODO 组件初始化 赋值操作
def choosePatha(self,evt):
if self.monitor_running == True:
return False
directory_path = filedialog.askdirectory(
title="选择文件夹"
)
# 显示选定的文件夹路径
if directory_path:
# print("选择的文件夹:", directory_path)
# 更新界面或其他逻辑
self.ui.tk_input_m0c6lpcn.delete(0, tk.END)
self.ui.tk_input_m0c6lpcn.insert(0, directory_path)
def choosePathb(self, evt):
if self.monitor_running == True:
return False
directory_path = filedialog.askdirectory(
title="选择文件夹"
)
# 显示选定的文件夹路径
if directory_path:
# print("选择的文件夹:", directory_path)
# 更新界面或其他逻辑
self.ui.tk_input_m0c6n6vi.delete(0, tk.END)
self.ui.tk_input_m0c6n6vi.insert(0, directory_path)
def startCopy(self,evt):
if self.monitor_running == True:
return # 如果监控已经在运行,则不执行任何操作
fromPath = self.ui.tk_input_m0c6lpcn.get()
savePath = self.ui.tk_input_m0c6n6vi.get()
if fromPath == "" or savePath == "":
showinfo(title="提示", message="两个路径都需要输入!")
return False
if fromPath in savePath:
showinfo(title="提示", message="保存的路径不能选择到需要复制的文件夹内!")
return False
self.stop_event = threading.Event()
self.thread = threading.Thread(target=self.update_counter, args=(fromPath,savePath))
self.thread.daemon = True
self.thread.start()
self.ui.tk_button_m0c6lvy7.config(state=tk.DISABLED)
self.ui.tk_button_m0c6nb3j.config(state=tk.DISABLED)
self.ui.tk_button_m0c7djh2.config(state=tk.DISABLED)
self.ui.tk_input_m0c6lpcn.config(state="readonly")
self.ui.tk_input_m0c6n6vi.config(state="readonly")
self.monitor_running = True
def update_counter(self, fromPath,savePath):
self.CreateDir(savePath)
fileNum = self.count_files_in_directory(fromPath)
self.ui.tk_progressbar_m0d8ueyu.config(length=fileNum,maximum=fileNum)
self.ui.tk_progressbar_m0d8ueyu["value"] = 0
self.ui.update()
self.CopyFile(fromPath, savePath, fileNum)
successfulText = "成功复制了" + str(fileNum) + "个文件"
self.ui.tk_label_m0dhb051.config(text=successfulText)
showinfo(title="提示", message="复制成功!")
# 按钮启用
self.ui.tk_button_m0c6lvy7.config(state=tk.NORMAL)
self.ui.tk_button_m0c6nb3j.config(state=tk.NORMAL)
self.ui.tk_button_m0c7djh2.config(state=tk.NORMAL)
self.ui.tk_input_m0c6lpcn.config(state="normal")
self.ui.tk_input_m0c6n6vi.config(state="normal")
self.monitor_running = False
self.stop_event.set() # 设置停止事件
self.stop_event.clear()
#置0
self.ui.tk_progressbar_m0d8ueyu["value"] = 0
self.ui.update()
return True
def count_files_in_directory(self,directory_path):
# 初始化文件计数
file_count = 0
# 使用 os.walk 遍历文件夹及其子目录
for root, dirs, files in os.walk(directory_path):
# 对于每个目录,累加文件数量
file_count += len(files)
# 返回文件总数
return file_count
def CopyFile(self,filepath, newPath, fileNum):
# 获取当前路径下的文件名,返回List
fileNames = os.listdir(filepath)
for file in fileNames:
# 将文件命加入到当前文件路径后面
newDir = filepath + '/' + file
# 如果是文件
if os.path.isfile(newDir):
newFile = newPath + '/'+ file
shutil.copyfile(newDir, newFile)
self.ui.tk_progressbar_m0d8ueyu["value"] += 1
self.ui.update()
successfulText = "进度:" + str(self.ui.tk_progressbar_m0d8ueyu["value"]) + " / " + str(fileNum)
self.ui.tk_label_m0dhb051.config(text=successfulText)
# 如果不是文件,递归这个文件夹的路径
else:
self.CopyFile(newDir, newPath, fileNum)
def CreateDir(self,path):
isExists = os.path.exists(path)
# 判断结果
if not isExists:
# 如果不存在则创建目录
os.makedirs(path)
# print(path + ' 目录创建成功')
# else:
# 如果目录存在则不创建,并提示目录已存在
# print(path + ' 目录已存在')