在 Tkinter 中使用 root.after 和 root.mainloop 的正确方法 [英] Correct way of using root.after and root.mainloop in Tkinter

查看:151
本文介绍了在 Tkinter 中使用 root.after 和 root.mainloop 的正确方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个需要每 5 分钟自动刷新一次的 tkinter 界面.到目前为止没有问题,您只需要执行以下操作:

I have a tkinter interface that needs to be automatically refreshed every 5 minutes. So far there is no problem, you would just have to do something like:

root.after(300000, function_to_run, args_of_fun_to_run)

问题是我必须在无限"时间内执行此操作.场景是 GUI 将在连接到电视的 PC 上运行,在我的办公室中 24/7 显示一些信息.这工作了大约 8 小时,然后我收到以下错误:

The problem is that I have to do this for an "infinite" amount of time. The scenario is that the GUI will running on a PC attached to a TV displaying some info 24/7 in my office. This works for around 8 hours and then I get the following error:

现在,我知道回溯一直到我的一个使用 matplotlib 的自定义模块中的一行.我的自定义模块都没有使用任何循环,所以我知道错误不是直接来自其中一个(如果我错了,请纠正我),所以它一定是我无限次重复该函数造成的.这是我的主函数中的代码:

Now, I know that the traceback goes all the way to a line in one of my custom modules that uses matplotlib. None of my custom modules uses any loops so I knw that the error does not directly come from one of them (please correct me if I'm wrong), so it must be from me repeating the function an infinite amount of time. This is the code from my main function:

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

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

What can I modify here to avoid this error??

谢谢!

正如许多人所建议的,我已经将 mainloop 调用移到了 main 函数之外.我的代码的最后几行现在看起来像这样:

As many have suggested, I have moved the mainloop call outside of the main function. The las few lines of my code look like this now:

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

except:
    logging.exception("Oops:")

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

The root.after call remains inside the function. After running it like this, it closes after 5 minutes. Does anyone know why the mainloop is not being called?

推荐答案

如何使用mainloopafter

简而言之,正确的方法是确保您只调用 mainloop 一次,然后让您的周期函数在完成工作后自行重新安排:

How to use mainloop and after

In short, the correct way is to make sure you call mainloop precisely once, and then have your periodic function reschedule itself when it's done working:

root = tk.Tk()
...
def do_one_iteration():
    ... your code here ...
    root.after(300000, do_one_iteration)

root.mainloop()

去除递归

您的代码中的问题是您在调用 after 的同一函数中调用了 mainloop -- 您在每次迭代期间创建了一个无限循环你的无限循环.这是问题的直接原因.您需要将 mainloop 的调用移出 maininterface 函数,以便它只被调用一次.

Remove the recursion

The problem in your code is that you have the call to mainloop in the same function that calls after -- you're creating an infinite loop during each iteration of your infinite loop. This is the immediate cause of the problem. You need to move the call to mainloop out of the maininterface function so that it is only called once.

您还需要稍微重构maininterface.看起来您一直在创建新的小部件而没有破坏旧的小部件,这是内存泄漏.最终你的程序将耗尽内存.当然,每 5 分钟只创建一个新小部件并不严重,但对于必须 24/7 全天候运行的应用来说,它会随着时间的推移而累积.

You also need to refactor maininterface a bit. It appears you keep creating new widgets without ever destroying old widgets, which is a memory leak. Eventually your program will run out of memory. Of course, creating just one new widget every five minutes isn't egregious, but it will add up over time for an app that must run 24/7.

通常最好简单地更新现有小部件而不是销毁和重新创建它们,但如果是这样,您需要做的不仅仅是调用 grid_forget.所做的只是将它们从视图中删除,但它们仍在占用内存.如果您真的想删除旧小部件,请调用 destroy 方法.

It's usually best to simply update existing widgets rather than to destroy and recreate them, but if you are, you need to do more than just call grid_forget. All that does is remove them from view, but they are still taking up memory. If you truly want to delete old widgets, call the destroy method.

您显然试图用 file.close 关闭文件,但正确的语法是 file.close()(注意尾括号)

You are apparently attempting to close a file with file.close, but the proper syntax is file.close() (note the trailing parenthesis)

这篇关于在 Tkinter 中使用 root.after 和 root.mainloop 的正确方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆