从 tkinter 中的按钮开始和停止线程中的重复任务

Start and stop a repeating task in a thread from a button in tkinter

我想从 tkinter 制作的 GUI 开始一个任务,应该 运行 每 10 秒。 GUI 有一个开始按钮和一个停止按钮,带有一个停止线程的事件。 我正在使用调度模块和线程来避免冻结 GUI。

from functools import partial
import tkinter as tk
from threading import Thread, Event, Lock
import schedule
import time
import os


class GUI():
    def __init__(self,master):
        self.master = master
        self.frame = tk.Frame(self.master)
        
        self.button1 = tk.Button(text='Start', command=partial(run_threaded,experiment), width=20,height=2,bg="gray",fg="black")
        self.button1.pack()
        self.button2 = tk.Button(text='Stop', command=stop_button, width=20,height=2,bg="gray",fg="black")
        self.button2.pack()
    
def job():
    print("Task started") 
    print("Task completed") 
        
def experiment():
    schedule.every(10).seconds.do(job)
    while 1:
        schedule.run_pending()
    
def run_threaded(job_func):
    job_thread = Thread(target=job_func)
    job_thread.start()
    if stop_threads.is_set():
        job_thread.join()
        job_thread = None

def start_button():
    run_threaded(experiment)
    
def stop_button():
    global stop_threads
    stop_threads.set()

def main():
    global stop_threads
    thread1=None
    stop_threads = Event()
    root = tk.Tk()
    app = GUI(root)
    root.mainloop()

if __name__ == '__main__':
    main()

任务在 10 秒后开始并定期重复,但停止按钮不起作用,我希望进程立即开始,没有初始延迟。

此外,每隔一段时间我运行它,任务启动但没有出现GUI。

有没有更好的方法来完成这个?

尝试这样的事情:

import tkinter as tk
from time import sleep
from functools import partial
from threading import Thread

running_job = False


def job():
    print("Task started") 
    print("Task completed") 

def experiment():
    while running_job:
        job()
        # I changed it to 1 sec to make it easier to test
        sleep(1)


class GUI:
    def __init__(self,master):
        self.master = master
        self.frame = tk.Frame(self.master)

        command = partial(run_threaded, experiment)
        self.button1 = tk.Button(text="Start", command=command)
        self.button1.pack()
        self.button2 = tk.Button(text="Stop", command=stop_button)
        self.button2.pack()


def run_threaded(job_func):
    global running_job
    running_job = True
    job_thread = Thread(target=job_func, daemon=True)
    job_thread.start()

def stop_button():
    global running_job
    running_job = False

if __name__ == "__main__":
    root = tk.Tk()
    app = GUI(root)
    root.mainloop()

它使用一个名为 running_job 的全局变量。当 running_jobTrue 时,experiment 中的 while 循环可以 运行。转为False时,experiment停止。这种方法的问题是,如果您在 job 函数中使用 tkinter widgets/variables,tkinter 可能会崩溃。

另一种方法是使用 .after 脚本来代替,但要使其正常工作,job 函数的执行时间不会太长。