Почему Tkinter не показывает, что мой секундомер увеличивается?

#user-interface #tkinter #while-loop #timer

Вопрос:

Я успешно создал функцию, которая выводит (как print() ) время секундомера от 0 до 5 секунд.

Я хочу использовать Tkinter для отображения вывода секундомера в окне ввода при нажатии кнопки «Пуск». По какой-то причине, когда вы нажимаете «Пуск», он просто загружается в течение 5 секунд, а затем отображает только последний вывод (5,0 сек).

Почему он не показывает результат, динамически изменяющийся от 0,0 до 5,0 сек? Я прилагаю код сюда — я не могу понять, почему это не работает…

 from tkinter import *
import time

win = Tk()  # creating a window instance
win.title('stopwach')

def start_timer():
    """begin timer from 1-5"""
    start_time = time.time()
    stopwatch=0 # initializing
    while stopwatch <= 5:
        current_time = time.time()
        stopwatch = current_time - start_time
        entry_field.delete(0, END)
        entry_field.insert(0, str(format(stopwatch, ".1f"))   " sec")
        time.sleep(0.01)
    

entry_field = Entry(win, width=35, borderwidth=5)
entry_field.pack()

message_1 = Label(win, text='5 second stopwatch')
message_1.pack()

button_1 = Button(win, text='START', command=start_timer)
button_1.pack()


win.mainloop()
 

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

1. нельзя использовать циклы в том же потоке, что и tkinter, они блокируют основной цикл, однако вы можете использовать либо .update() метод (не рекомендуется), либо .after() циклы, либо другой поток

Ответ №1:

Вы не можете использовать time.sleep tkinter, так как он блокирует графический интерфейс до его завершения. Для tkinter вы должны использовать root.after , например , это:

 def start_timer():
    """begin timer from 1-5"""
    global start_time, stopwatch
    start_time = time.time()
    stopwatch=0 # initializing
    tick_timer()

def tick_timer():
    global start_time, stopwatch
    if stopwatch <= 5:
        current_time = time.time()
        stopwatch = current_time - start_time
        entry_field.delete(0, END)
        entry_field.insert(0, "%.1f" % stopwatch   " sec")
        win.after(100, tick_timer) #Wait 100ms then run again
 

Это разбивает таймер на две функции. start_timer инициализирует переменные, а затем вызывает tick_timer . Это делает то же самое, что и раньше, но в конце я использовал win.after вместо time.sleep того, чтобы tick_timer снова вызывать функцию через 100 мс. Затем это работает, как и ожидалось.