Как убить поток tkinter + thread

Помогите разобраться пожалуйста! Проблема заключается в неком непонимании работы языка... Есть программа написанная мной с помощью tkinter, я написал код так, что при старте работы создаётся root внутри которого сформированные вкладки, а затем вызываются классы этих вкладок и один из классов Area - некая рабочая область внутри которой вызывается бесконечный поток и происходит обновление каждый день в 00:00 часов. Код для примера работы программы:

import time
from threading import Thread
from tkinter import *
from tkinter import ttk
from tkinter.messagebox import showwarning, showinfo, askyesnocancel
import schedule

class Area():

    def __init__(self):
        self.top = Frame(frame1)
        self.top.pack(side=TOP, padx=15, fill=BOTH)
        self.text = ttk.Label(frame1, text='You: ',
                            font=('Times New Roman', 12, 'bold'),
                            justify="left")
        self.text.pack(in_=self.top, side=RIGHT)

        def scheduler():
            def job_session():
                self.text.configure(text=f'Misha')
            schedule.every().day.at("14:40").do(job_session)

            while True:
                schedule.run_pending()
                time.sleep(1)

        thread = Thread(target=scheduler)
        thread.start()


if __name__ == '__main__':
    root = Tk()

    notebook = ttk.Notebook()
    notebook.pack(expand=True, fill=BOTH)

    frame1 = ttk.Frame(notebook)
    frame2 = ttk.Frame(notebook)
    frame1.pack(fill=BOTH, expand=True)
    frame2.pack(fill=BOTH, expand=True)

    notebook.add(frame1, text='Area')
    notebook.add(frame2, text='Programm')


    def on_closing():
        result = askyesnocancel(title="Подтверждение выхода",
                                message="Закрыть программу помощник?")
        if result:
            root.destroy()


    root.protocol('WM_DELETE_WINDOW', on_closing)

    work_area = Area()

    root.mainloop()

Проблема в том, что при закрытии root процесс не прекращается и программа не завершается. Если запуск с IDE то при завершении принудительно через stop получаю естественно code -1. Я пробовал прописывать в root при выходе из программы, т.к. есть перехват выхода:

def on_closing():
    result = askyesnocancel(title="Подтверждение выхода",
                            message="Закрыть программу помощник?")
    if result:
        **добавлял sys.exit()**
        root.destroy()


root.protocol('WM_DELETE_WINDOW', on_closing)

Добавлял sys.exit() - но это никакого эффекта не даёт.. Не понимаю как мне завершить поток при закрытии root, если он внутри класса. Подскажите, как поправить. Переписывать полностью классы или программу тяжело, т.к. уже более 1500 строк кода..( Помогите с костылём..


Ответы (1 шт):

Автор решения: Сергей Кох

Запускаем schedule в фоновом режиме и для выхода из цикла используем Event Objects из модуля threading.

import time
import threading
from tkinter import *
from tkinter import ttk
from tkinter.messagebox import showwarning, showinfo, askyesnocancel
import schedule


def job_session():
    print('Hello from the background thread')
    time.sleep(10)


def on_closing():
    result = askyesnocancel(title="Подтверждение выхода",
                            message="Закрыть программу помощник?")
    if result:
        stop_run_continuously.set()
        root.destroy()


def run_continuously(interval=1):

    cease_continuous_run = threading.Event()

    class ScheduleThread(threading.Thread):
        @classmethod
        def run(cls):
            while not cease_continuous_run.is_set():
                schedule.run_pending()
                time.sleep(interval)

    continuous_thread = ScheduleThread()
    continuous_thread.start()
    return cease_continuous_run

class Area():

    def __init__(self):
        self.top = Frame(frame1)
        self.top.pack(side=TOP, padx=15, fill=BOTH)
        self.text = ttk.Label(frame1, text='You: ',
                            font=('Times New Roman', 12, 'bold'),
                            justify="left")
        self.text.pack(in_=self.top, side=RIGHT)



if __name__ == '__main__':
    root = Tk()

    notebook = ttk.Notebook()
    notebook.pack(expand=True, fill=BOTH)

    frame1 = ttk.Frame(notebook)
    frame2 = ttk.Frame(notebook)
    frame1.pack(fill=BOTH, expand=True)
    frame2.pack(fill=BOTH, expand=True)

    notebook.add(frame1, text='Area')
    notebook.add(frame2, text='Programm')

    root.protocol('WM_DELETE_WINDOW', on_closing)

    work_area = Area()

    schedule.every().day.at("15:25").do(job_session)
    stop_run_continuously = run_continuously()

    root.mainloop()

Правда если началось обновление, то придется подождать пока оно не закончиться.

→ Ссылка