Функция автозагрузки Tkinter порождает новый цикл каждый раз, когда он вызывается - PullRequest
0 голосов
/ 02 января 2019

У меня есть программа, которая тянет и отображает несколько значений обновления. У меня есть кнопка, которая вручную перезагружает необходимую информацию. Моя конечная цель - создать текстовое поле, в котором я могу ввести значение, и перезагружать программу каждые 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 голосов
/ 03 января 2019

Вопрос : я хочу, чтобы кнопка могла форсировать новый интервал

новый интервал вычисляется с использованием

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())
0 голосов
/ 03 января 2019

Одним из способов предотвращения возникшей проблемы является отключение кнопки после ее нажатия.

Мы можем запустить цикл 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...