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

如何避免执行函数时Toplevel窗口(启动屏)出现冻结?

解决Tkinter启动屏与进度条冻结问题

你的问题核心是耗时操作阻塞了Tkinter的主事件循环,导致启动屏和进度条无法刷新。即使尝试了threading.Thread,如果没正确处理UI线程的限制,依然会失效。Tkinter要求所有UI操作必须在主线程执行,子线程只能处理耗时逻辑,再通过主线程更新UI状态。

以下是修正后的代码:

import tkinter as tk
from tkinter import ttk
import threading

def loading_window():
    toplevel_window = tk.Toplevel(root)
    toplevel_window.overrideredirect(1)
    # 让启动屏居中显示(可选优化)
    window_width, window_height = 220, 80
    screen_width = root.winfo_screenwidth()
    screen_height = root.winfo_screenheight()
    x = (screen_width // 2) - (window_width // 2)
    y = (screen_height // 2) - (window_height // 2)
    toplevel_window.geometry(f"{window_width}x{window_height}+{x}+{y}")

    label = tk.Label(toplevel_window, text='请稍候')
    label.pack(padx=10, pady=5)

    progressbar = ttk.Progressbar(toplevel_window, orient=tk.HORIZONTAL, length=200, mode="indeterminate")
    progressbar.start()
    progressbar.pack(padx=10, pady=10)

    def check_process_status():
        if is_process_over.get():
            progressbar.stop()
            toplevel_window.destroy()
            return
        toplevel_window.after(100, check_process_status)
    
    toplevel_window.after(100, check_process_status)
    toplevel_window.grab_set()

def func2():
    # 模拟耗时操作
    for _ in range(250000000):
        pass
    # 子线程不能直接操作UI,用after通知主线程更新状态
    root.after(0, lambda: is_process_over.set(True))
    root.after(0, lambda: label.configure(text="完成"))

def func1():
    is_process_over.set(False)
    loading_window()
    # 将耗时操作放到子线程执行
    threading.Thread(target=func2, daemon=True).start()

root = tk.Tk()
is_process_over = tk.BooleanVar(value=False)

btn = tk.Button(root, text="执行任务", command=func1)
btn.pack(padx=10, pady=20)

label = tk.Label(root, text="等待任务开始")
label.pack(padx=10, pady=20)

root.mainloop()

关键修正点:

  • 耗时操作移至子线程:用threading.Thread把func2放到独立线程,避免阻塞主事件循环。
  • 子线程通过after更新UI:子线程不能直接修改Tkinter组件,必须通过root.after(0, ...)将UI操作委托给主线程执行。
  • 简化启动屏更新逻辑:不再手动调用progressbar.update(),而是通过after定期检查任务状态,同时依赖进度条自身的start()方法实现动画。
  • 启动屏居中优化:添加了窗口居中代码,提升用户体验(可选)。

注意事项:

  • 子线程中绝对不能直接调用任何Tkinter的UI方法,否则会导致程序崩溃或异常。
  • 使用daemon=True标记子线程,确保程序退出时子线程会自动终止。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 20:15:08