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

使用Thread后仍无法实时更新CustomTkinter中Label的问题求助

解决CustomTkinter实时更新下载进度不生效的问题

问题场景

尝试通过self.error_label实时显示YouTube视频的下载进度,虽然使用了Thread线程开启下载任务,但只有下载完成时才会显示“Download 100%”,中间的20%、48%等进度完全不更新。相关代码如下:

import customtkinter
from pytube import YouTube
import re
from threading import Thread


class App(customtkinter.CTk):
    def __init__(self):
        super().__init__()
        self._set_appearance_mode("System")

        self.geometry("720x480")
        self.title('PyTube')
        
        # Progress bar
        self.progressbar = customtkinter.CTkProgressBar(self, width=500)
        self.progressbar.set(0)
        self.progressbar.pack()

        #Error label
        self.error_label = customtkinter.CTkLabel(self, text='Welcome!')
        self.error_label.pack()

        #User input box
        ................

      
    def progress_callback(self, stream, chunk, bytes_remaining):
        total_size = stream.filesize
        bytes_downloaded = total_size - bytes_remaining
        percentage = bytes_downloaded / total_size * 100
        self.error_label.configure(text=f'Download {percentage}%')
    
        
    def youtube_video_download(self, link, res):
        yt = YouTube(link, on_progress_callback=self.progress_callback)
        vid = yt.streams.filter(progressive=True, resolution=res).first()
        vid.download()

        
    def Download(self):
        if self.link_validate(self.user_input.get()):
            if self.tabview.get() == 'Video':
                if self.video_quality.get() != '':
                    Thread(target=self.youtube_video_download, args=(self.user_input.get(), self.video_quality.get(), )).start()
                else:
                    self.error('Video quality is not selected!', 'red')
             


if __name__=="__main__":
    app = App()
    app.mainloop()

问题原因

Pytube的on_progress_callback回调函数是在子线程中执行的,而CustomTkinter(以及所有Tkinter衍生库)的UI组件只能在主线程中更新。直接在子线程里调用self.error_label.configure()会导致UI更新被阻塞,只有当子线程任务完成后,所有积压的UI更新才会一次性执行,所以看不到中间进度。

解决方案

使用CustomTkinter的self.after()方法,将UI更新的任务提交到主线程的事件循环中执行。修改后的progress_callback方法如下:

def progress_callback(self, stream, chunk, bytes_remaining):
    total_size = stream.filesize
    bytes_downloaded = total_size - bytes_remaining
    percentage = bytes_downloaded / total_size * 100
    # 用after将UI更新操作提交到主线程
    self.after(0, lambda: self.error_label.configure(text=f'Download {round(percentage, 1)}%'))

如果需要同时更新进度条,也可以把进度条的更新逻辑放进after的lambda里:

def progress_callback(self, stream, chunk, bytes_remaining):
    total_size = stream.filesize
    bytes_downloaded = total_size - bytes_remaining
    percentage = bytes_downloaded / total_size * 100
    # 同时更新标签文本和进度条进度
    self.after(0, lambda: (
        self.error_label.configure(text=f'Download {round(percentage, 1)}%'),
        self.progressbar.set(percentage / 100)
    ))

self.after(0, func)的作用是让主线程在当前事件循环的空闲时间立即执行func,确保所有UI操作都在主线程完成,这样就能实时显示下载进度了。

内容的提问来源于stack exchange,提问作者Rohit Dalal

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 18:01:07