Python ttkbootstrap进度条下载YouTube视频时不更新问题求助
解决YouTube视频下载工具进度条实时更新问题
问题根源
- 主线程阻塞:
mp4_720.download()是同步操作,会卡住UI主线程,导致进度更新无法实时显示 - ProgressBar未实例化存储:创建进度条时没有将其保存为类的实例变量,无法在回调中更新
- UI未强制刷新:更新进度后没有触发UI刷新,导致界面不会实时变化
- 百分比格式错误:计算后的百分比未格式化,显示的是原始小数,不符合预期
修改后的完整代码
import pathlib import threading from tkinter import ttk import ttkbootstrap as ttkb from ttkbootstrap.constants import * from tkinter.filedialog import askdirectory from pytube import YouTube class DataEntryForm(ttkb.Frame): def __init__(self, master): super().__init__(master, padding=(20,10)) self.pack(fill =BOTH, expand=YES) #application variables self.repertoireChoisi = ttkb.StringVar() #form variables self.URL = ttkb.StringVar(value="") self.repertoire = ttkb.StringVar(value="" ) #form header hdr_txt = "Entrez l'URL de la vidéo et le répertoire où les fichiers seront stockés" hdr = ttkb.Label(self, text=hdr_txt, width= 100) hdr.pack(fill = X, padx=10, pady=10) #form entries self.create_form_entry("url", self.URL) self.create_progressbar(0) self.create_repertoire_entry("repertoire", self.repertoire) self.create_buttonbox() def create_form_entry(self, label, variable): """Create a single form entry""" container = ttkb.Frame(self) container.pack(fill=X, expand=YES, pady=5) lbl = ttkb.Label(master=container, text=label.title(), width=10) lbl.pack(side=LEFT, padx=5) ent = ttkb.Entry(master=container, textvariable=self.URL, width = 80) ent.pack(side=LEFT, padx=5, fill=X, expand=YES) rep_button = ttkb.Button( master = container, text = "Télécharger", style=SUCCESS, command = self.start_download_thread, width= 20 ) rep_button.pack(side=LEFT, padx=5, fill=X, expand=NO) def create_repertoire_entry(self, label, variable): container = ttkb.Frame(self) container.pack(fill=X, expand=YES, pady=5) lbl = ttkb.Label(master=container, text="Repertoire", width=10) lbl.pack(side=LEFT, padx=5) ent = ttkb.Entry(master=container, width=80, textvariable=variable) ent.pack(side=LEFT, padx=5, fill=X, expand=NO) rep_button = ttkb.Button( master = container, text = "Rechercher", style=SUCCESS, command = self.on_search, width= 20 ) rep_button.pack(side=LEFT, padx=5, fill=X, expand=NO) def create_progressbar(self, percent): """Create a progress bar""" # 保存进度条为实例变量 self.progress = ttk.Progressbar(self, maximum=100) self.progress.pack(fill=X,expand=YES, pady=(15,10)) self.percentage_label = ttk.Label(self, width = 40, text=f"{percent}%") self.percentage_label.pack(fill=BOTH, expand=TRUE, padx = 215) def create_buttonbox(self): """Create the application buttonbox""" container = ttkb.Frame(self) container.pack(fill=X, expand=YES, pady=(15, 10)) sub_btn = ttkb.Button( master=container, text="Envoyer", command=self.on_submit, style =SUCCESS, width=10, ) sub_btn.pack(side=RIGHT, padx=5) sub_btn.focus_set() cnl_btn = ttkb.Button( master=container, text="Cancel", command=self.on_cancel, style=DANGER, width=10, ) cnl_btn.pack(side=RIGHT, padx=5) def on_submit(self): """Print the contents to console and return the values.""" print("URL:", self.URL.get()) print("repertoire:", self.repertoire.get()) return self.URL.get(), self.repertoire.get() def on_cancel(self): """Cancel and close the application.""" self.quit() def on_search(self): """Search directory where to download the files.""" self.repertoireChoisi.set(askdirectory( initialdir="/", title="Sélectionnez un répertoire" ) ) self.repertoire.set(self.repertoireChoisi.get()) def start_download_thread(self): """启动子线程执行下载,避免阻塞主线程""" threading.Thread(target=self.on_download, daemon=True).start() def on_download(self): """get data from the video and dl it.""" video = YouTube(self.URL.get(), on_progress_callback=self.on_progress) filters = video.streams.filter(file_extension='mp4') mp4_720 = filters.get_highest_resolution() mp4_720.download(self.repertoire.get()) def on_progress(self, stream, chunk, bytes_remaining): """Update the progress bar.""" total_size = stream.filesize bytes_downloaded = total_size - bytes_remaining percentage = int((bytes_downloaded / total_size) * 100) # 更新进度条和百分比文本 self.progress['value'] = percentage self.percentage_label.config(text=f"{percentage}%") # 强制刷新UI self.update_idletasks() if __name__ == "__main__": app = ttkb.Window("Téléchargement de Vidéo YouTube", "superhero", resizable=(False, False)) DataEntryForm(app) app.mainloop()
关键修改点说明
- 使用子线程执行下载:新增
start_download_thread方法,通过threading.Thread把下载操作放到子线程,避免阻塞UI主线程 - 保存ProgressBar实例:将进度条保存为
self.progress,百分比标签保存为self.percentage_label,方便在回调中更新 - 正确注册进度回调:创建
YouTube对象时直接传入on_progress_callback参数,替代原有的register_on_progress_callback - 格式化百分比并刷新UI:计算后将百分比转为整数,更新进度条值和标签文本,调用
update_idletasks()强制UI刷新
内容的提问来源于stack exchange,提问作者Bernard Grosperrin
相关产品推荐
相关产品推荐

