#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 не позволяет мне задавать больше вопросов.