Закрытие окна и последующее его открытие в цикле

Хочу написать программу, используя tkinter, которая служит для напоминаний, создал словарь с определенными часами и минутами, по достижению которых появляется диалоговое окно, в котором есть кнопка, после нажатия на которую окно закрывается, но оно должно появиться снова, когда настанет следующее совпадение со временем в словаре, но столкнулся с проблемой зависания окна при нажатии на кнопку. Код:

from datetime import datetime
from tkinter import *
from tkinter import messagebox as mb
import time

def quit():
    root.quit()

root = Tk()
root.title("Notification")
Label(text="Alarm", width=30, height=3).pack()
a = Label(text='', width=20, height=3)
a.pack()
Button(text="Ok", width=10, command=quit).pack()

tim = {
    "1": [9, 10],
    "2": [10, 10],
    "3": [11, 10],
    "4": [14, 10],
    "5": [15, 10],
    "6": [16, 20],
    "test": [15, 2],
    "test2": [15, 3]
}

if root.winfo_screenwidth() > 1920:
    w = root.winfo_screenwidth()//4-200
else:
    w = root.winfo_screenwidth()//2-150
h = root.winfo_screenheight()//2-100

root.geometry('400x150+{}+{}'.format(w, h))


while True:
    current_d = datetime.now()
    if current_d.hour == tim["test"][0] and current_d.minute == tim["test"][1] and current_d.second == 0:
        a.config(text="Point №1")
        root.mainloop()

    if current_d.hour == tim["test2"][0] and current_d.minute == tim["test2"][1] and current_d.second == 0:
        a.config(text="Point №2")
        root.mainloop()

ps Тестировал работу без цикла, и все работало корректно, окно закрывалось и никаких ошибок и зависаний не было


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

Автор решения: insolor

В оконном приложении не должно быть никаких вечных циклов в основном потоке - должен быть только вызов функции mainloop(), внутри которой есть свой "вечный" цикл (выполняющийся все время, пока существует главное окно).

Если нужно выполнять какое-то действие периодически (например, сравнивать время с заданным), то планируйте выполнение функции с этим действием с помощью метода root.after(). Пример:

import tkinter as tk
from datetime import datetime, timedelta

root = tk.Tk()


def check_time(start_time, time_delta):
    if datetime.now() - start_time >= time_delta:
        root.deiconify()  # Время истекло - отобразить окно
    else:
        root.after(500, check_time, start_time, time_delta)  # Не истекло - проверить время еще раз через 500 мс


def hide():
    root.withdraw()  # Скрыть окно

    # Запланировать выполнение функции check_time через 500 миллисекунд
    root.after(500, check_time, datetime.now(), timedelta(seconds=5))  
    # Все параметры кроме первых будут переданы в функцию check_time в момент ее вызова


tk.Button(root, text="Скрыть на 5 сек", command=hide).pack()

root.mainloop()
→ Ссылка