重新创建小部件时,Tkinter窗口不断崩溃

时间:2016-10-10 16:47:11

标签: python tkinter thread-safety

我最近开始测试Tkinter制作简单的应用程序,这些应用程序可以挂钩到API并为用户提供该API的数据样本。我想要的一件事是这个窗口偶尔刷新,更新信息,以便它永远不会过时。

然而,似乎tkinter窗口经常崩溃。没有错误或消息被返回,它在不稳定的时间变得没有响应。添加大量小部件会使崩溃更快发生,但是随着小部件数量的不同,最终似乎无论如何都会发生。

为了使其间隔自动刷新,我设置了一个可以调用tkinter App的redraw方法的线程。根据我的研究,我知道tkinter不是线程安全的,但我认为当我每隔30秒只调用一个线程调用需要花费一些时间运行的重绘方法时,这不会是一个问题。

这是我的应用程序的最小版本,在几次尝试重绘后会崩溃。我的实际数据最终只有大约15个小部件和崩溃,但是将数量提高到非常高的值会使崩溃更早发生,并且更容易进行测试。

from Tkinter import *

from threading import Thread, Event

REFRESH_INTERVAL = 30

class App(Frame):

    names = ["test"] * 50

    def __init__(self, master):
        Frame.__init__(self, master)

        self.frame = master
        self.table = None
        self.redraw()


    def redraw(self):
        if self.table:
            self.table.destroy()

        new_frame = Frame(self.frame)
        new_frame.pack()
        self.table = new_frame

        for code in self.names:
            label = Label(new_frame, text=code)
            label.pack()


class Refresher(Thread):

    def __init__(self, event, app):
        Thread.__init__(self)
        self.stopped = event
        self.app = app

    def run(self):
        while not self.stopped.wait(REFRESH_INTERVAL):
            print("Refreshing...")
            self.app.redraw()


def main():
    root = Tk()
    app = App(root)
    app.pack(side=TOP, fill="both", expand=True)

    stop_flag = Event()
    refresher = Refresher(stop_flag, app)
    refresher.start()
    root.mainloop()
    stop_flag.set()


if __name__ == "__main__":
    main()

1 个答案:

答案 0 :(得分:0)

事实证明,Tkinter不喜欢单独的线程进行这样的调用。相反,建议改为使用after方法。

This answer详细介绍了它,但它实际上是一种在延迟后调用函数的方法。它可以在发送时添加到我的重绘功能中,以便在延迟后不断添加触发器以重新运行该功能。

def redraw(self):
    if self.table:
        self.table.destroy()

    new_frame = Frame(self.frame)
    new_frame.pack()
    self.table = new_frame

    for code in self.names:
        label = Label(new_frame, text=code)
        label.pack()
    self.master.after(REFRESH_INTERVAL, self.redraw)