Итак, у меня есть базовый графический интерфейс Tkinter с ползунком масштабирования. Я хочу использовать таймер для выборки значения шкалы каждую 1 секунду (что должно имитировать акселератор автомобиля).
Как я могу добавить таймер в свой код?
import tkinter as tk
import ttkbootstrap as ttk
SCALE_VALUE_MIN = -20
SCALE_VALUE_MAX = 100
SCALE_VALUE_DEFAULT = 0
MAX_FORWARD_ACC = 3 # m/s^2
MAX_BACKWARD_ACC = MAX_FORWARD_ACC / 3
MAX_FORWARD_SPEED = 220 / 3.6 # 220 km/h to m/s
MAX_BACKWARD_SPEED = 20 / 3.6 # 20 km/h to m/s
def scaleupdate(value):
output_str.set(value)
def scalerelease(value):
scale.set(SCALE_VALUE_DEFAULT)
window = ttk.Window(themename= 'journal')
window.title('Demo')
window.geometry('300x150')
# frame
frame1 = ttk.Frame(master = window)
# min_label
min_label = ttk.Label(master = frame1, text = str(SCALE_VALUE_MIN))
min_label.pack(side = 'left', padx = 10)
# scale
scalevar = tk.DoubleVar()
scale = ttk.Scale(master = frame1, variable = scalevar, from_= SCALE_VALUE_MIN, to = SCALE_VALUE_MAX, orient = 'horizontal', command = scaleupdate)
scale.set(SCALE_VALUE_DEFAULT)
scale.bind('<ButtonRelease-1>', scalerelease)
scale.pack(side = 'left', padx = 10)
# max_label
max_label = ttk.Label(master = frame1, text = str(SCALE_VALUE_MAX))
max_label.pack(side = 'left', padx = 10)
frame1.pack()
# label
output_str = tk.StringVar()
label = ttk.Label(master = window, font = 'Calibri 16', text = 'Scale value', textvariable = output_str)
label.pack(pady = 5)
# run
window.mainloop()
Я пытался измерить время (используя timeit.timer_default()) и вычислить скорость по разнице во времени, но это сработало только после изменения значения шкалы.
Мне нужен независимый внешний таймер, который проверяет значение ползунка и соответствующим образом обновляет скорость.
Я читал о threading.timer, но не понимаю, как интегрировать его с основным циклом.
Отвечает ли это на ваш вопрос? Как запустить свой собственный код вместе с циклом событий Tkinter?. Единственная проблема с этим подходом заключается в том, что он не очень точен, но достаточно хорош для большинства задач.
Поможет ли вам оставить комментарий #scale.bind('<ButtonRelease-1>', scalerelease)
?
Вы можете использовать метод after
tkinter, чтобы запланировать запуск функции через заданное количество миллисекунд. Вы можете настроить повторяющийся цикл, вызвав after
из функции, вызываемой after
.
Например, рассмотрим эту функцию:
def sample(window, delay):
# call sample(window, delay) after 'delay' milliseconds
window.after(delay, sample, window, delay)
# get the value and display it
value = scalevar.get()
print(f"Sample: {value:.2f}")
Эта функция запланирует повторный запуск через 1000 мс (1 секунду). Затем он получит текущее значение и выведет его на консоль. Сначала выполняется планирование, чтобы объем обработки, выполняемой в функции, не вызывал слишком большого отклонения.
Однако имейте в виду, что tkinter не является системой реального времени и не гарантирует, что функция будет запущена точно в запрошенное время. В этом случае единственной гарантией является то, что функция будет вызвана через 1000 мс. Это может означать 1000,1 мс или больше. Поскольку tkinter является однопоточным, функцию нельзя вызвать во время выполнения другого кода.
Если вы добавите эту функцию в свой код, а затем вызовете ее один раз, она будет выполняться каждую секунду, пока вы не выйдете из программы:
# run
sample(window, 1000)
window.mainloop()
похоже, метод
after
— это именно то, что вам нужно