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

tkinter类与frame架构下GUI无响应,求多线程同步更新进度条方案

Tkinter调用耗时服务端方法GUI无响应问题解决

我是Python/tkinter新手,使用Python 3.8版本开发时遇到如下问题:调用运行在服务端的CSF.addOrders方法时,该方法根据订单数量不同,执行时长在10秒到5分钟不等,期间应用标题栏会显示「未响应」,且进度条pb1无法更新,用户无法感知程序仍在正常运行。
我需要实现CSF.addOrders运行期间pb1缓慢更新、且该方法执行完成后立即终止进度条更新的效果。我查阅了大量tkinter无响应相关的帖子,但由于我的代码采用类和frame架构,未找到适配的解决方案。

修复后可运行完整代码

import tkinter as tk
import tkinter.ttk  as ttk
import ClientServer_Functions as CSF
import threading
import queue
import logging
import time

# Log File
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s:%(message)s', datefmt='%Y-%m-%d %H:%M:%S')

# create the handlers and call logger.addHandler(logging_handler)
if not logger.handlers:
    file_handler = logging.FileHandler('GUI_Logger.log')
    file_handler.setLevel(logging.INFO)
    file_handler.setFormatter(formatter)

    stream_handler = logging.StreamHandler()
    stream_handler.setFormatter(formatter)

    logger.addHandler(file_handler)
    logger.addHandler(stream_handler)

logger.propagate = False

class sample(tk.Tk):   
    def __init__(self):
        tk.Tk.__init__(self)
        self.shared_data = {
            "fName": tk.StringVar(),  # userInfo[0][0] 
            "username": tk.StringVar(),  # userInfo[0][1]
            "password": tk.StringVar(),  # userInfo[0][2]
            "custSym": tk.StringVar(),  # userInfo[0][3]
            "email": tk.StringVar(),  # userInfo[0][4]
            "sPath": tk.StringVar(),  # userInfo[0][5]
            "FTP_User": tk.StringVar(),  # userInfo[0][6]
            "FTP_Password": tk.StringVar(),   # userInfo[0][7]
            "fType": tk.StringVar()
            }
        container = tk.Frame(self)
        container.pack(side="top", fill="both", expand=True)
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)
        
        global bgColor
        bgColor = "black"
        self.frames = {}
        for F in (Trade, blank): #there are other frames I create that are not listed
            frame = F(container, self)
            self.frames[F] = frame
            frame.config(bg=bgColor)
            frame.grid(row=0, column=0, sticky="nsew")
        self.show_frame(Trade)

    def get_page(self, page_class):
        return self.frames[page_class]
    
    def show_frame(self, c):
        frame = self.frames[c]
        frame.tkraise()
        
class Trade(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller=controller
        
        tk.Label(self, bg=bgColor).pack()
        tk.Label(self, text="TRADES", bg=bgColor, fg="yellow").pack(pady=20)
        tk.Button(self, text="Orders", command=lambda: [self.setFType("Orders"), self.files()]).pack(pady=10)
        self.statusbar = tk.Label(self)
        self.statusbar.pack(side=tk.BOTTOM, fill=tk.X)
    
    def setFType(self, fType):
        self.controller.shared_data["fType"].set(fType)    
    
   
    def aOrders(self, ls):
        l = ls[0]
        print("starting t1")
        time.sleep(1)
        result, msg, FTP_outFile = CSF.addOrders(l,"u", "p", "fp", "sp", "c") 
        return result, msg, FTP_outFile
        
   
    def files(self): 
        fType = self.controller.shared_data["fType"].get()
        self.statusbar['text'] = "Running..."
        pb1 = ttk.Progressbar(self, orient=tk.HORIZONTAL, length=250, mode='determinate')
        pb1['value'] += 10
        pb1.place(relx=.25, rely=.88)
        
        que = queue.Queue()
        t1 = threading.Thread(target = lambda q, arg : q.put(self.aOrders(arg)), args = (que, [logger, 2]))
        t1.start()
        for x in range(100):
            if t1.is_alive():
                print("update pb1")
                pb1['value'] += 2
                tk.Tk.update(self)
                time.sleep(1)
            else:
                print(que.get())
                break
        print("do balance of program...")

class blank(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller=controller 
        
if __name__ == "__main__":
    app = sample()
    app.geometry("500x500+500+150")
    app.mainloop()

核心实现逻辑

  • 把耗时的CSF.addOrders调用放到独立子线程执行,避免阻塞Tkinter主线程的GUI渲染
  • 主线程循环检测子线程运行状态,子线程存活时逐秒更新进度条数值,调用tk.Tk.update()主动刷新GUI
  • 子线程执行完成后立即终止进度条更新,通过队列获取子线程的返回结果

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 18:06:03