在 Tkinter 中使用 root.after 和 root.mainloop 的正确方法
Correct way of using root.after and root.mainloop in Tkinter
我有一个tkinter界面需要每5分钟自动刷新一次。到目前为止没有问题,你只需要做这样的事情:
root.after(300000, function_to_run, args_of_fun_to_run)
问题是我必须在 "infinite" 时间内完成此操作。场景是 GUI 将 运行 在连接到电视的 PC 上显示我办公室 24/7 的一些信息。这工作了大约 8 个小时,然后我收到以下错误:
现在,我知道回溯一直到我的一个使用 matplotlib 的自定义模块中的一行。 None 我的自定义模块使用了任何循环,所以我知道错误不是直接来自其中一个(如果我错了请纠正我),所以它一定是我无限量地重复函数时间。这是我的主要功能的代码:
from tkinter import *
from tkinter import ttk
import logging
import datetime
import sys
sys.path.append(r'C:\Users\me\Desktop\seprated sla screens')
import sla_main as sla
import main_frame as mf
import sla_grid as sg
import incoming_volume as iv
import outgoing_volume as ov
import read_forecast as fc
import get_headers as hd
import vol_graph as vg
import out_graph as og
import add_graph as ag
import sla_reduction_email as sre
###################################
###################################
###################################
###################################
runs = 0
def maininterface(f_size, pic_x, pic_y):
global runs
global root
start = str(datetime.datetime.now().date()) + ' ' + str(datetime.timedelta(hours=6))
screen = sla.slamain(start)
if runs == 0:
root = mf.mainframe(f_size)
sg.sla_grid(screen, f_size, root)
file = open('titles in queue.txt', 'r')
in_q = file.read()
file.close
ttk.Label(root, text=in_q, anchor=CENTER, width=15, font=('times', f_size, 'bold')).grid(column=6, row=2, sticky=E)
if runs > 0:
###################################
#deletes all rows before making the calculations
for label in root.grid_slaves():
if int(label.grid_info()["row"]) > 1:
label.grid_forget()
sg.sla_grid(screen, f_size, root)
file = open('titles in queue.txt', 'r')
in_q = file.read()
file.close
ttk.Label(root, text=in_q, anchor=CENTER, width=15, font=('times', f_size, 'bold')).grid(column=6, row=2, sticky=E)
###################################
#all this part is just info for the graph and the graph
incoming = iv.incomingvolume(start)
outgoing = ov.outgoingvolume(start)
forecast = fc.readforecast()
headers = hd.getheaders()
vg.volgraph(forecast, incoming, headers, pic_x, pic_y)
#og.outgraph(forecast, outgoing, headers, pic_x, pic_y)
ag.addgraph("vol_graph.png", root, 1)
#ag.addgraph("out_graph.png", root, 2)
runs = runs + 1
globals().update(locals())
print(str(datetime.datetime.now()))
root.after(300000, maininterface, f_size, pic_x, pic_y)
root.mainloop()
logging.basicConfig(level=logging.DEBUG, filename='error_log.txt')
try:
maininterface(28, 23.5, 6)
except:
logging.exception("Oops:")
我可以在这里修改什么来避免这个错误?
谢谢!
编辑:
正如许多人所建议的那样,我已将 mainloop 调用移到 main 函数之外。我的最后几行代码现在看起来像这样:
try:
maininterface(28, 23.5, 6)
root.mainloop()
except:
logging.exception("Oops:")
root.after 调用保留在函数内部。 运行这样后,5分钟后关闭。有谁知道为什么没有调用主循环?
在函数外调用主循环。
如何使用mainloop
和after
简而言之,正确的方法是确保您准确调用 mainloop
一次,然后让您的周期函数在完成工作后重新安排自身:
root = tk.Tk()
...
def do_one_iteration():
... your code here ...
root.after(300000, do_one_iteration)
root.mainloop()
删除递归
您的代码中的问题是您在调用 after
的同一个函数中调用了 mainloop
-- 您在无限循环的每次迭代中创建了一个无限循环。这是问题的直接原因。您需要将对 mainloop
的调用移出 maininterface
函数,以便只调用一次。
修复内存泄漏
您还需要稍微重构一下 maininterface
。看起来您一直在创建新的小部件而没有销毁旧的小部件,这是内存泄漏。最终你的程序会 运行 内存不足。当然,每五分钟只创建一个新小部件并不算过分,但随着时间的推移,对于必须 运行 24/7.
的应用程序来说,它会累积起来
通常最好只是更新现有的小部件,而不是销毁并重新创建它们,但如果是这样,您需要做的不仅仅是调用 grid_forget
。所做的只是将它们从视图中移除,但它们仍在占用内存。如果您真的想删除旧的小部件,请调用 destroy
方法。
正确关闭文件
您显然是在尝试使用 file.close
关闭文件,但正确的语法是 file.close()
(注意尾随的括号)
我有一个tkinter界面需要每5分钟自动刷新一次。到目前为止没有问题,你只需要做这样的事情:
root.after(300000, function_to_run, args_of_fun_to_run)
问题是我必须在 "infinite" 时间内完成此操作。场景是 GUI 将 运行 在连接到电视的 PC 上显示我办公室 24/7 的一些信息。这工作了大约 8 个小时,然后我收到以下错误:
现在,我知道回溯一直到我的一个使用 matplotlib 的自定义模块中的一行。 None 我的自定义模块使用了任何循环,所以我知道错误不是直接来自其中一个(如果我错了请纠正我),所以它一定是我无限量地重复函数时间。这是我的主要功能的代码:
from tkinter import *
from tkinter import ttk
import logging
import datetime
import sys
sys.path.append(r'C:\Users\me\Desktop\seprated sla screens')
import sla_main as sla
import main_frame as mf
import sla_grid as sg
import incoming_volume as iv
import outgoing_volume as ov
import read_forecast as fc
import get_headers as hd
import vol_graph as vg
import out_graph as og
import add_graph as ag
import sla_reduction_email as sre
###################################
###################################
###################################
###################################
runs = 0
def maininterface(f_size, pic_x, pic_y):
global runs
global root
start = str(datetime.datetime.now().date()) + ' ' + str(datetime.timedelta(hours=6))
screen = sla.slamain(start)
if runs == 0:
root = mf.mainframe(f_size)
sg.sla_grid(screen, f_size, root)
file = open('titles in queue.txt', 'r')
in_q = file.read()
file.close
ttk.Label(root, text=in_q, anchor=CENTER, width=15, font=('times', f_size, 'bold')).grid(column=6, row=2, sticky=E)
if runs > 0:
###################################
#deletes all rows before making the calculations
for label in root.grid_slaves():
if int(label.grid_info()["row"]) > 1:
label.grid_forget()
sg.sla_grid(screen, f_size, root)
file = open('titles in queue.txt', 'r')
in_q = file.read()
file.close
ttk.Label(root, text=in_q, anchor=CENTER, width=15, font=('times', f_size, 'bold')).grid(column=6, row=2, sticky=E)
###################################
#all this part is just info for the graph and the graph
incoming = iv.incomingvolume(start)
outgoing = ov.outgoingvolume(start)
forecast = fc.readforecast()
headers = hd.getheaders()
vg.volgraph(forecast, incoming, headers, pic_x, pic_y)
#og.outgraph(forecast, outgoing, headers, pic_x, pic_y)
ag.addgraph("vol_graph.png", root, 1)
#ag.addgraph("out_graph.png", root, 2)
runs = runs + 1
globals().update(locals())
print(str(datetime.datetime.now()))
root.after(300000, maininterface, f_size, pic_x, pic_y)
root.mainloop()
logging.basicConfig(level=logging.DEBUG, filename='error_log.txt')
try:
maininterface(28, 23.5, 6)
except:
logging.exception("Oops:")
我可以在这里修改什么来避免这个错误?
谢谢!
编辑:
正如许多人所建议的那样,我已将 mainloop 调用移到 main 函数之外。我的最后几行代码现在看起来像这样:
try:
maininterface(28, 23.5, 6)
root.mainloop()
except:
logging.exception("Oops:")
root.after 调用保留在函数内部。 运行这样后,5分钟后关闭。有谁知道为什么没有调用主循环?
在函数外调用主循环。
如何使用mainloop
和after
简而言之,正确的方法是确保您准确调用 mainloop
一次,然后让您的周期函数在完成工作后重新安排自身:
root = tk.Tk()
...
def do_one_iteration():
... your code here ...
root.after(300000, do_one_iteration)
root.mainloop()
删除递归
您的代码中的问题是您在调用 after
的同一个函数中调用了 mainloop
-- 您在无限循环的每次迭代中创建了一个无限循环。这是问题的直接原因。您需要将对 mainloop
的调用移出 maininterface
函数,以便只调用一次。
修复内存泄漏
您还需要稍微重构一下 maininterface
。看起来您一直在创建新的小部件而没有销毁旧的小部件,这是内存泄漏。最终你的程序会 运行 内存不足。当然,每五分钟只创建一个新小部件并不算过分,但随着时间的推移,对于必须 运行 24/7.
通常最好只是更新现有的小部件,而不是销毁并重新创建它们,但如果是这样,您需要做的不仅仅是调用 grid_forget
。所做的只是将它们从视图中移除,但它们仍在占用内存。如果您真的想删除旧的小部件,请调用 destroy
方法。
正确关闭文件
您显然是在尝试使用 file.close
关闭文件,但正确的语法是 file.close()
(注意尾随的括号)