Python 使用 "after" 方法更新标签时,Tkinter 会在一段时间后冻结

Python Tkinter freezes after a while when updating labels using "after" method

我正在使用 ttk (tkinter) 的 after 方法实时 update/create 一些标签。我已经根据此 SO question 改编了我的代码,但我注意到一段时间后屏幕停止响应。我不确定多长时间,但是当我启动该程序时,一切似乎都运行良好。当我在没有关闭 UI 的情况下睡觉时,在 return 上它冻结并在几秒钟后解冻,让我在冻结前几秒钟进行交互。

我不知道是什么导致了这种行为,但我怀疑我在哪里进行 sqlite 查询以显示数据库中的总记录。或者也许我在一个函数中做了太多的标签更新。请参阅下面的 update_lbl 方法。

要预览我正在尝试实现的目标,请参阅 image

class ReptoUI(ttk.Notebook):
    def __init__(self, parent):
        ttk.Notebook.__init__(self, parent)
        self.parent = parent

        self.parent.title("Repto Mail Checker")

        self.frame1 = ttk.Frame(self.parent, borderwidth=2, relief='groove')  # first page,
        self.frame1.grid(column=0, row=0, sticky=(N, S, E, W))

        self.con()  # configure columns
        self.frame2 = ttk.Frame(self.parent, borderwidth=2, relief='raised')  # second page,
        self.frame2.grid(column=9, row=11, columnspan=11, rowspan=11)
        self.add(self.frame1, text="Checker")
        self.add(self.frame2, text="Sender")

        self.mail_server = StringVar()
        self.mail_port = IntVar()
        self.protocol = StringVar()
        self.folder = StringVar()
        self.mail_type = StringVar()

        self.username = StringVar()
        self.password = StringVar()
        self.log_checker = BooleanVar()
        self.interval = IntVar()

        self.initUI()
        self.centerWindow()

    def con(self):
        for i in range(11):
            self.frame1.grid_columnconfigure(i, weight=1)
            # self.frame1.grid_rowconfigure(i, weight=1)


    def update_lbl(self):
        session = setup_db()
        total = session.query(Contact).count() # my guess is here
        allcountlbl = ttk.Label(self.frame1, text=total)
        allcountlbl.grid(column=7, row=4)

        if not self.username.get():
            username = ''
        else:
            username = self.username.get()

        # if isinstance(username, StringVar):
        #     username = ""

        if not self.folder.get():
            folder = self.folder
        else:
            folder = self.folder.get()
        print type(username)

        addrlbl = ttk.Label(self.frame1, text=username)
        addrlbl.grid(column=2, row=4)

        dirlbl = ttk.Label(self.frame1, text=folder)
        dirlbl.grid(column=4, row=4, sticky=W)
        self.frame1.after(1000, self.update_lbl)
    def statusUI(self):

        workinglbl = ttk.Label(self.frame1, text="Working on:")
        workinglbl.grid(column=1, row=4)
        self.update_lbl()

        boxlbl = ttk.Label(self.frame1, text="Folder:")
        boxlbl.grid(column=3, row=4)
    def initUI(self):
        # First page design tab/frame f1
        self.serverUI()
        self.mailUI()
        self.startUI()
        self.statusUI()

编辑: 这是调用 setup_db 时发生的情况。 我不确定 sqlalchemy 是否处理连接关闭,因为我可以做不同的变化 session.close()engine.dispose()

def setup_db():
    engine = create_engine('sqlite:///records.db')
    Base.metadata.bind = engine
    DBSession = sessionmaker(bind=engine)
    session = DBSession()
    return session

虽然可能不是导致此问题的唯一原因,但您有某种内存泄漏。每一秒你都在创建三个新标签。这意味着仅 10 分钟后,您将创建 1,800 个标签小部件。虽然我认为 tkinter 可以处理几千个小部件,但您每小时要创建超过 10,000 个小部件。

您应该只创建一次标签,然后只在每秒调用的函数中更改它们的文本属性。

您可能还应该将 session = setup_db() 移出循环。我怀疑是否有必要每秒创建一个新会话。创建一个持续整个程序生命周期的会话。