You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python ttkbootstrap进度条下载YouTube视频时不更新问题求助

解决YouTube视频下载工具进度条实时更新问题

问题根源

  1. 主线程阻塞:mp4_720.download()是同步操作,会卡住UI主线程,导致进度更新无法实时显示
  2. ProgressBar未实例化存储:创建进度条时没有将其保存为类的实例变量,无法在回调中更新
  3. UI未强制刷新:更新进度后没有触发UI刷新,导致界面不会实时变化
  4. 百分比格式错误:计算后的百分比未格式化,显示的是原始小数,不符合预期

修改后的完整代码

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()

关键修改点说明

  1. 使用子线程执行下载:新增start_download_thread方法,通过threading.Thread把下载操作放到子线程,避免阻塞UI主线程
  2. 保存ProgressBar实例:将进度条保存为self.progress,百分比标签保存为self.percentage_label,方便在回调中更新
  3. 正确注册进度回调:创建YouTube对象时直接传入on_progress_callback参数,替代原有的register_on_progress_callback
  4. 格式化百分比并刷新UI:计算后将百分比转为整数,更新进度条值和标签文本,调用update_idletasks()强制UI刷新

内容的提问来源于stack exchange,提问作者Bernard Grosperrin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 14:22:24