在Tkin中正确使用root.after和root.mainloop的方法

2024-04-28 15:02:28 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个tkinter接口,需要每5分钟自动刷新一次。到目前为止还没有问题,你只需要做如下事情:

root.after(300000, function_to_run, args_of_fun_to_run)

问题是我必须在“无限”的时间内这样做。这种情况下,图形用户界面将运行在一台连接到电视的电脑上,在我的办公室24/7显示一些信息。这项工作大约8小时,然后我得到以下错误:

enter image description here

现在,我知道回溯一直到我的一个自定义模块中使用matplotlib的一行。我的自定义模块没有使用任何循环,因此我知道错误不是直接来自其中一个模块(如果我错了,请纠正我),因此必须是我无限次地重复函数。这是我主要功能的代码:

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:")

我可以在这里修改什么来避免这个错误??

谢谢!

编辑:

正如许多人所建议的,我已经将主循环调用移到主函数之外。我代码的最后几行现在看起来是这样的:

try:
    maininterface(28, 23.5, 6)
    root.mainloop()

except:
    logging.exception("Oops:")

root.after调用仍保留在函数内部。像这样运行后,5分钟后关闭。有人知道为什么不调用主循环吗?


Tags: inimportsizedatetimeloggingasrunsroot
2条回答

在函数外部调用主循环。

如何使用mainloopafter

简而言之,正确的方法是确保精确地调用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()(注意后面的括号)

相关问题 更多 >