相关文章推荐

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

1 人关注

我有一个tkinter界面,需要每5分钟自动刷新一次。到目前为止还没有问题,你只需要做这样的事情。

root.after(300000, function_to_run, args_of_fun_to_run)

问题是,我必须在 "无限 "的时间内做到这一点。情况是,GUI将在一台连接到电视的PC上运行,在我的办公室里全天候显示一些信息。这工作了大约8个小时,然后我得到以下错误。

现在,我知道回溯一直延伸到我的一个使用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()

root.after的调用仍然在函数内。像这样运行后,5分钟后就关闭了。有谁知道为什么mainloop没有被调用?

5 个评论
在函数外调用mainloop。
可能与你的问题无关,但 file.close 并没有任何作用。你需要 file.close()
@MalikBrahimi,如果这就是答案,请把它作为答案发布。
如果它在5分钟后关闭, mainloop is 正在运行,而且有东西导致主窗口被破坏。
我没有得到任何异常,而且我的代码中没有任何类似于root.destroy()的地方 O.o
python
python-3.x
tkinter
rodrigocf
rodrigocf
发布于 2015-04-01
2 个回答
Bryan Oakley
Bryan Oakley
发布于 2015-04-01
已采纳
0 人赞同

How to use mainloop and after

简而言之,正确的方法是确保你精确地调用 mainloop 一次,然后让你的周期性函数在完成工作后重新安排自己。

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

Remove the recursion

你代码中的问题是,你在调用mainloop的同一个函数中调用了after。-- 你在无限循环的每一次迭代中创造了一个无限循环。这就是问题的直接原因。你需要将对mainloop的调用移出maininterface函数,这样它就只被调用一次。

Fix the memory leak

你还需要重构一下maininterface。你似乎一直在创建新的部件而没有销毁旧的部件,这是一个内存泄漏。最终你的程序会耗尽内存。当然,每五分钟创建一个新的小部件并不可怕,但对于一个必须全天候运行的应用程序来说,随着时间的推移,它将会越来越多。

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

 
推荐文章