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

Python CustomTkinter YouTube下载器程序冻结问题求助

解决CustomTkinter YouTube下载器点击按钮后冻结的问题

问题核心在于GUI主线程被耗时操作阻塞:你的startdownload函数在GUI主线程中完成YouTube对象初始化、视频解析及下载等耗时任务,这些操作会占用主线程资源,导致界面完全失去响应,直到所有耗时操作结束才会恢复。

解决方案:用子线程处理耗时任务

Tkinter(包括CustomTkinter)是单线程GUI框架,所有UI操作必须在主线程执行,但耗时的网络/IO任务要放到独立子线程中,避免阻塞主线程。同时注意:子线程不能直接更新UI,需要通过after方法调度到主线程执行更新操作。

修改后的完整代码

import tkinter
import customtkinter
from pytube import YouTube
import threading


def startdownload():
    # 禁用下载按钮,防止重复点击
    download.configure(state="disabled")
    # 重置状态文本
    finishlabel.configure(text="")
    number.configure(text="0%")
    bar.set(0)
    
    def download_task():
        try:
            ytLink = link.get()
            # 耗时操作在子线程执行
            ytObject = YouTube(ytLink, on_progress_callback=on_progress)
            video = ytObject.streams.get_lowest_resolution()
            
            # 调度主线程更新标题
            app.after(0, lambda: title.configure(text=ytObject.title))

            video.download()
            # 下载完成后更新UI
            app.after(0, lambda: finishlabel.configure(text="下载完成"))
        except Exception as e:
            app.after(0, lambda: finishlabel.configure(text="链接无效或下载失败"))
        finally:
            # 重新启用下载按钮
            app.after(0, lambda: download.configure(state="normal"))
    
    # 创建并启动子线程
    threading.Thread(target=download_task, daemon=True).start()


def on_progress(stream, chunk, bytes_remaining):
    total_size = stream.filesize
    bytes_downloaded = total_size - bytes_remaining
    percentage_of_completion = bytes_downloaded / total_size * 100
    per = str(int(percentage_of_completion))
    
    # 调度主线程更新进度,避免线程安全问题
    app.after(0, lambda: number.configure(text=per + "%"))
    app.after(0, lambda: bar.set(float(percentage_of_completion) / 100))


customtkinter.set_appearance_mode("dark")
customtkinter.set_default_color_theme("blue")

app = customtkinter.CTk()
app.geometry("720x480")
app.title("YouTube 视频下载器")

title = customtkinter.CTkLabel(app, text="输入视频链接")
title.pack(padx=10, pady=10)

url_var = tkinter.StringVar()
link = customtkinter.CTkEntry(app, width=350, height=40, textvariable=url_var)
link.pack()

finishlabel = customtkinter.CTkLabel(app, text="")
finishlabel.pack()

number = customtkinter.CTkLabel(app, text="0%")
number.pack()

bar = customtkinter.CTkProgressBar(app, width=400)
bar.set(0)
bar.pack(padx=10, pady=10)

download = customtkinter.CTkButton(app, width=200, text="下载", command=startdownload)
download.pack(padx=10, pady=10)

app.mainloop()

关键修改点说明

  • 引入threading模块:创建子线程执行download_task函数,把所有耗时的网络/IO操作放到子线程中,主线程只负责UI响应。
  • 禁用下载按钮:防止用户重复点击触发多个下载任务,下载完成后重新启用。
  • 用app.after(0, ...)调度UI更新:子线程不能直接修改UI组件,通过after方法将UI更新操作放入主线程的事件队列,确保线程安全。
  • 异常处理优化:捕获具体异常并给出更清晰的提示,同时在finally块中恢复按钮状态,避免按钮一直处于禁用状态。

内容的提问来源于stack exchange,提问作者Little Frezno

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 18:32:40