Tkinter自动重载函数在每次调用时都会产生新的循环

时间:2019-01-02 19:17:39

标签: python tkinter

我有一个可以拉出并显示几个更新值的程序。我有一个按钮,可以手动重新加载必要的信息。我的最终目标是要有一个文本字段,我可以在其中键入一个值,并使程序每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()

我的问题是,每当我按下masterReloadButton时,都会启动一个新的“重新加载循环”。

例如:

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

Properly working Loop, ~10 seconds intervals

这是我按masterReloadButton(大约5秒钟进入循环)后的输出。现在有两个循环同时发生,偏移量约为5秒。它确实捕获了新的循环值,但也完全生成了一个新的循环。

Concurrent loops: unwanted result


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

在我看来,每次我按下按钮时,都会创建一个新的masterReload()流程。我需要每次都破坏该过程,或者重新组织我的代码以免发生这种情况,但是我不确定该怎么做。

谢谢。

2 个答案:

答案 0 :(得分:1)

防止出现此问题的一种方法是在按下按钮后将其禁用。

我们可以启动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来停止循环。

答案 1 :(得分:1)

  

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

新间隔是使用

计算的
int(reloadTimer.get())*1000

因此,无需单击Button


要强制设置新的间隔,您必须取消当前正在运行的reload_after()循环并开始一个新的循环。

使用两个功能,masterReload(),点击reload_after()即可取消/启动 Button
另一个reload_after()通过循环显示值。

  

取消.after(...上的Button 单击:

    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())