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()
移出循环。我怀疑是否有必要每秒创建一个新会话。创建一个持续整个程序生命周期的会话。
我正在使用 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()
移出循环。我怀疑是否有必要每秒创建一个新会话。创建一个持续整个程序生命周期的会话。