Python Tkinter autoreload函数每次生成新循环';这叫什么

Python Tkinter autoreload函数每次生成新循环';这叫什么,python,tkinter,Python,Tkinter,我有一个程序,拉和显示几个更新值。我有一个按钮,可以手动重新加载必要的信息。我的最终目标是有一个文本字段,我可以在其中键入一个值,并让程序每隔x秒重新加载一次。我的问题出现在设置新的循环间隔值时 以下是我遇到的问题的一个基本示例: import tkinter as tk import datetime class MainApplication(tk.Frame): def __init__(self, parent, *args, **kwargs): tk.Fra

我有一个程序,拉和显示几个更新值。我有一个按钮,可以手动重新加载必要的信息。我的最终目标是有一个文本字段,我可以在其中键入一个值,并让程序每隔
x
秒重新加载一次。我的问题出现在设置新的循环间隔值时

以下是我遇到的问题的一个基本示例:

import tkinter as tk
import datetime

class MainApplication(tk.Frame):
    def __init__(self, parent, *args, **kwargs):
        tk.Frame.__init__(self, parent, *args, **kwargs)
        self.parent = parent
        reloadTimer=tk.Entry(root)
        reloadTimer.pack(side=tk.LEFT)
        reloadTimer.insert(10,10)

        def masterReload():
            print("LOADING " + str(datetime.datetime.now()))
            parent.after(int(reloadTimer.get())*1000, masterReload)

        masterReloadButton = tk.Button(root, text='Set', command=lambda:masterReload())
        masterReloadButton.pack()

        masterReload()

if __name__ == "__main__":
    root = tk.Tk()
    MainApplication(root).pack()
    root.mainloop()

我的问题是,每次我按下
主重新加载按钮
,一个新的“重新加载循环”就开始了

例如:

这是我按下任何按钮之前的输出。循环间隔约为10秒

这是我按下主重新加载按钮后的输出,大约进入循环5秒。现在有两个循环同时发生,偏移量约为5秒。它确实获取了新的循环值,但它也完全生成了一个新的循环


我需要“设置”按钮,因为否则只有在重新加载时才会检索新的计时器值。如果有人输入一个非常大的数字,程序将需要很长时间才能接受一个新值

在我看来,每次我按下按钮时都会创建一个新的
masterReload()
进程。我需要每次都销毁这个过程,或者重新组织代码,这样就不会发生这种情况,但我不知道该怎么做


提前感谢。

防止出现问题的一种方法是在按下按钮后禁用该按钮

我们可以启动
master_reload
循环,同时使用
lambda
表达式禁用按钮

这是您的代码清理了一点与按钮设置为禁用后,第一次按下

更新:现在在循环后立即更新,而不是等待最后一个循环完成

import tkinter as tk
import datetime


class MainApplication(tk.Tk):
    def __init__(self):
        super().__init__()
        self.reload_timer = tk.Entry(self)
        self.reload_timer.pack(side='left')
        self.reload_timer.insert(10, 10)
        self.active_after = None
        self.time_tracker = None
        self.btn = tk.Button(self, text='Set', command=self.set_time_tracker)
        self.btn.pack()

    def master_reload(self):
        print("LOADING {}".format(datetime.datetime.now()))
        self.active_after = self.after(self.time_tracker*1000, self.master_reload)

    def set_time_tracker(self):
        x = self.reload_timer.get()
        if x.isdigit():
            if int(x) > 0:
                if self.active_after is not None:
                    self.after_cancel(self.active_after)
                    self.active_after = None
                    self.time_tracker = int(x)
                    self.master_reload()
                else:
                    self.time_tracker = int(x)
                    self.master_reload()
            else:
                self.after_cancel(self.active_after)
                self.active_after = None
        else:
            if self.active_after is not None:
                self.after_cancel(self.active_after)
                self.active_after = None


if __name__ == "__main__":
    MainApplication().mainloop()
这里的好处是,您可以随时更改时间,而不会导致重复循环,甚至可以通过键入零
0
或任何字母并按set停止循环

问题:我希望该按钮能够强制新的间隔

新的间隔是使用

int(reloadTimer.get())*1000
因此,无需点击
按钮


要强制新的间隔,您必须取消当前运行的
reload\u after()
循环并开始新的循环

使用两个函数,
masterReload()
cancel/start
reload\u after()
按钮上单击。
另一个,
reload\u after()
,通过循环显示值

取消
。在(…
打开
按钮后
单击:


@stovfl我不明白,你能确切地说明我应该禁用什么,以及我应该怎么做吗?@stovfl我仍然希望在程序启动后能够单击按钮并获取新值。@stovfl是的,但我希望能够注入新的间隔值。如果有人输入100000,他们必须等待100000秒,然后才能执行b可以输入不同的值。我希望按钮能够强制执行新的间隔,但我不知道如何在不重新调用函数本身的情况下执行此操作
lambda:masterReload()
太过分了。最好将其改为
masterReload
谢谢你,迈克,第二位代码正是我想要的——能够在任何时候编辑间隔+1@EmilioGarcia我准备向类中添加一个方法,它将允许您取消现有的after计时器,这样您就不需要等待它经过b在设置新计时器之前。当我第一次测试您的代码时,我认为我能够做到。嗯。(当我第一次测试时,计时器值在控制台中重新打印,但我现在看不到它,或者在您的帖子编辑历史记录中。我读取了打印(x)进行测试)。但是,现在当我重新测试时,我似乎遇到了与最初相同的问题,在重新设置计时器变量后,双循环开始。请参见此处:我已更新了代码,因此它将立即更新后循环。新代码似乎工作得很好。我已标记为已解决。再次感谢。
    self.after_id = None

    def masterReload():
        # New intervall

        # Cancel previous reload_after() loop
        if self.after_id:
            self.after_cancel(self.after_id)
            self.after_id = None

        # Start new reload_after() loop
        parent.after(0, reload_after)

    def reload_after():
        print("LOADING " + str(datetime.datetime.now()))
        self.after_id = parent.after(int(reloadTimer.get())*1000, reload_after)

    masterReloadButton = tk.Button(root, text='Set', command=lambda:masterReload())