Как предотвратить отсутствие ответа программы tkinter при запуске цикла while

#python #tkinter

#python #tkinter

Вопрос:

Я создал напоминание о лекарствах в tkinter.Это работает, но когда я нажимаю кнопку «Уведомить», моя программа зависает и сообщает, что не отвечает, но программа все еще работает.

 from tkinter import *
from plyer import notification
from datetime import datetime
import tkinter.messagebox as msg

root = Tk()
root.title("Medicine reminder")


def notify():
    msg.showinfo("Reminder Set",f"You will be notified at {timeSlider.get()}. Make sure that you don't close the program")
    while True:
        hour = datetime.now().hour
        if hour == timeSlider.get():
            notification.notify(
                title=f"Take your medicine {medicine.get()}",
                message=f"You have scheduled it for {timeSlider.get()}",
                # displaying time
                timeout=15)
            break


Label(text="Medicine Reminder", font="comicsans 20 bold").pack(anchor="w", padx=10, pady=10)
medicine = StringVar()
medicine_entry = Entry(font="comicsans 20", textvariable=medicine)
medicine_entry.insert(0, "Name of medicine")
medicine_entry.pack(anchor="w", padx=10, pady=5)
timeSlider = Scale(from_=0, to=24, orient=HORIZONTAL)
Label(text="Enter the time you want to get notified at:", font="comicsans 15").pack(anchor="w", padx=10)
timeSlider.pack(anchor="w", padx=10)
Button(text="Notify me", font="comicsans 15 bold", relief=SUNKEN, borderwidth=6, command=notify).pack(anchor="w",
                                                                                                      pady=15, padx=10)

root.mainloop()
  

Комментарии:

1. Я думаю, что while цикл вызывает проблему, попробуйте использовать after

2. Можете ли вы рассказать, как использовать после … но он также должен работать с циклом while .. как я могу заставить его работать с циклом while

Ответ №1:

Проблема с вашим кодом заключалась в том, что вы использовали бесконечный цикл с while , который выполняется в том же потоке, что и tkinter , следовательно, он не может запустить окно, поскольку окно занято выполнением цикла while, использование after которого tkinter встроено, является одним из способов решения этой проблемы.

Метод 1 (с использованием after ):

 def notify():
    global hour
    msg.showinfo("Reminder Set",f"You will be notified at {timeSlider.get()}. Make sure that you don't close the program")
    hour = datetime.now().hour
    root.after(timeSlider.get()*3600000,alert) #converting hour to ms

def alert():    
    notification.notify(
        title=f"Take your medicine {medicine.get()}",
        message=f"You have scheduled it for {timeSlider.get()}",
        # displaying time
        timeout=15)
  

after() метод в основном принимает два аргумента:

  • ms — время для запуска функции
  • func — функция, которая будет запускаться после завершения данного мс.

Оставшаяся часть кода остается прежней

Метод 2 (многопоточность):

 import threading
....
Button(text="Notify me", font="comicsans 15 bold", relief=SUNKEN, borderwidth=6, command=threading.Thread(target=notify).start).pack(anchor="w",
  

Просто внесите изменения в аргумент buttons command , а остальной код останется неизменным. Это поможет, но тогда с потоковой обработкой это все равно может выглядеть неэффективно, поэтому я рекомендую использовать метод 1.

Надеюсь, вы развеяли свои сомнения, если возникнут еще какие-либо ошибки, дайте мне знать.

Приветствия

Комментарии:

1. Что это после… можете ли вы объяснить, и мы не можем написать это с помощью цикла while

2. Ну, я сделал поиск в Google о root.after и я понял root.after. Спасибо, так мы узнаем новые вещи.

3. Но timeslider.get уже находится в целочисленной форме, поэтому нет необходимости вводить его

4. @Vasu Потоковая передача — это ничего особенного, как обычный поток, представьте, что машины проходят через поток, и они попали в аварию, поэтому поток может прерваться, точно так же, ваш tkinter запускается в одном потоке, и ваш while цикл выполняется с ним, что приводит к зависанию потока, но с threading вы создаете новый поток для этой функции с помощью while и, следовательно, поток с tkinter проходит гладко, в то время как поток с while циклом заморожен, и это не имеет значения для другого потока.

5. Я прошу вас, пожалуйста, поднять вопрос, поскольку StackOverflow не позволяет мне задавать больше вопросов.