I have for you what I hope is an interesting question/problem.
I am trying to "replay" a data set on a variable speed. First, look at this code:
import time
import numpy as np
#Replay Time Speed
s=10;
#Total Sample Time Array in Tenths of a Second
t=[]
for tenths in np.arange(0, 50.1, 0.1):
t.append(tenths)
#Time of Events (last element is just to stop loop)
eventsTime=[5.4, 10.0, 37.8, 40.5, 49.2, 50.1]
#Data Replay
eventIndex = 0
for tenths in t:
if tenths >= eventsTime[eventIndex]:
print(f"{round(tenths ,2)} - Event!")
if eventIndex < len(eventsTime)-1:
eventIndex = eventIndex 1
else:
print(round(tenths,2))
time.sleep(0.1/s)
By changing variable s I can print out faster or slower the time array elements. It's fairly neat.
However, I am trying to expand this to Tkinter, and I am not sure if it is even possible. Here is my attempt. You'll find the same loop of above embedded into the object at the function Update(), currently it breaks Python. I've dared to try using time.sleep() but didn't work.
from tkinter import *
import time
import numpy as np
import pandas as pd
class sensorMenu:
def __init__(self, controlMenu, timeArray, enventsTimeArray, speed):
#Tkinter
self.controlGUI = controlMenu
self.controlGUI.title('Control')
self.controlGUI.geometry("300x100")
#Inputs
self.timeAarray = timeArray
self.enventsTimeArray = enventsTimeArray
self.replaySpeed = round(0.1/speed)
#Layout
self.t1 = Label(self.controlGUI, text="Data Replay", font=("lucida 11 bold"))
self.play = Button(self.controlGUI, text="Play", command=lambda:[self.Start(), self.Update()])
self.t1.pack()
self.play.pack()
def Start(self):
#Visual
self.replay= Toplevel()
self.replay.title('Data Time')
self.c = Canvas(self.replay, width=200, height=200)
self.c.configure(bg='grey', highlightthickness=0)
#Timer
self.format = (f"Calibri {str(int(15))} bold")
self.replayTimeProgress = (f" 0.0 / {str(self.timeAarray[-1])} ")
self.timer = self.c.create_text(80, 100, text=self.replayTimeProgress, fill="black", font=("lucida 11 bold"))
self.eventIndex = 0
self.c.pack()
def Update(self):
#HOW?
for tenths in self.timeAarray:
if tenths >= self.enventsTimeArray[self.eventIndex]:
self.c.itemconfigure(self.timer, text="EVENT", fill="red")
if self.eventIndex < len(self.enventsTimeArray)-1:
self.eventIndex = self.eventIndex 1
self.replayTimeProgress = (f" {str(tenths)} / {str(self.timeAarray[-1])} ")
self.c.itemconfigure(self.timer, text=self.replayTimeProgress, fill="red")
self.replay.after(1, self.Update)
if __name__ == "__main__":
t=[]
for tenths in np.arange(0, 50.1, 0.1):
t.append(tenths)
eventsTime=[5.4, 10.0, 37.8, 40.5, 49.2, 50.1]
s=10;
controlMenu = Tk()
expData=sensorMenu(controlMenu, t, eventsTime, s)
controlMenu.mainloop()
What do you think?
Thank you for your time!
CodePudding user response:
Note that .after()
is not the same as sleep()
, it is a scheduler. So you should not call .after()
in a for loop. Also it is better not using loop in a tkinter main thread as it will block the tkinter .mainloop()
.
Note also that the first argument of .after()
is in milliseconds.
Below is the required changes to fix the freezing issue:
class sensorMenu:
def __init__(self, controlMenu, timeArray, enventsTimeArray, speed):
...
self.replaySpeed = speed # instead of round(0.1/speed)
...
...
def Update(self, i=0):
# don't use for loop
if i < len(self.timeAarray):
tenths = self.timeAarray[i]
if tenths >= self.enventsTimeArray[self.eventIndex]:
self.c.itemconfigure(self.timer, text="EVENT", fill="red")
if self.eventIndex < len(self.enventsTimeArray)-1:
self.eventIndex = self.eventIndex 1
self.replayTimeProgress = (f" {tenths:.1f} / {self.timeAarray[-1]} ")
self.c.itemconfigure(self.timer, text=self.replayTimeProgress, fill="red")
self.replay.after(self.replaySpeed, self.Update, i 1)