Reputation: 219
Goal: 30 minutes of timed activity that cycles through a series of alternating slow and intense exercises. The window starts by displaying a countdown timer starting at 30 minutes. The exercise starts with 30 seconds of "slow" activity - with the word "Slow" displayed below the timer. It then continues with 60 seconds of an intense exercise. Then 30 seconds of slow pace, followed by 60 seconds of a different intense exercise, and so on. In all, 4 different intense exercises each alternating with a slow pace.
I've assembled the code below. I don't believe it is intuitive. I don't like bouncing around methods and I feel there are methods out there that can be used to make this more efficient. On a practical level, this doesn't work well as the timer and the message (i.e. slow / exercise # displayed) start to become out of synch. I've researched python blogs and keep "hearing" something about Tkinter not being multithreaded. I'm guessing that the after(x,y) becomes compromised as the countdown thread takes up resources.... Not really sure. Also, I'd like to add a tone after each method as an audio queue for the "athletes" Anyway, thanks in advance for looking at my crude code.
import Tkinter as tk
class ExampleApp(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.label = tk.Label(self, text="", width=10, font= ("Helvetica",72), background='yellow', fg = 'red')
self.label2 = tk.Label(self, text="", width=10, font=("Helvetica",72), background='yellow', fg = 'blue')
self.label.pack()
self.label2.pack()
self.remaining = 0
self.countdown(1800) # the 30 minutes countdown initialization
self.run = True
def countdown(self, remaining = None):
if self.remaining == 1799: # marker that starts the methods series
self.start()
if remaining is not None:
self.remaining = remaining
if self.remaining >= 1:
mins = int(self.remaining/60)
#rsecs = self.remaining - mins * 60 #could use this
rsecs = self.remaining % 60 #same results as t - mins * 60
self.remaining = self.remaining -1
self.after(1000, self.countdown)
self.label.configure(text ="%.2f" % (mins + rsecs / 100.0))
else:
self.label.configure(text="Stop")
def start(self):
app.after(0, self.slow1)
return
def slow1(self):
self.label2.configure(text="Slow" )
app.after(30000, self.fast1)
return
def fast1(self):
self.label2.configure(text="Exercise 1" )
app.after(61000, self.slow2)
return
def slow2(self):
self.label2.configure(text="Slow" )
app.after(31000, self.fast2)
return
def fast2(self):
self.label2.configure(text="Exercise 2" )
app.after(61000, self.slow3)
return
def slow3(self):
self.label2.configure(text="Slow" )
app.after(30000, self.fast3)
return
def fast3(self):
self.label2.configure(text="Exercise 3" )
app.after(60000, self.slow4)
return
def slow4(self):
self.label2.configure(text="Slow" )
app.after(30000, self.fast4)
return
def fast4(self):
self.label2.configure(text="Exercise 4" )
app.after(60000, self.slow1)
return
if __name__ == "__main__":
app = ExampleApp()
app.title("Intense Workout")
app.geometry('550x550+200+200')
app.configure(background='yellow')
app.mainloop()
Upvotes: 1
Views: 380
Reputation: 386342
There are many ways to solve this problem, and you don't need threads. Here is one idea:
Start with a data structure that defines the intervals. For example:
intervals = [[30, "slow"], [60, "intense"], [30, "slow"], [60, "intense]]
Next, set up a simple timer function that is called once a second. At each second it displays the number and the string that is at the head of the list. The number represents the time left. In that timer function, subtract one from the number. If it becomes zero, remove that element from the list. Have this function call itself one second later using after
, stopping when the data structure becomes empty (ie: when there is only one pair left and the number drops to zero).
The following gives you an idea about how to implement this. The code can be made better, but the point is to illustrate how to iterate over a data structure using after
, not to necessarily give a production quality example.
import Tkinter as tk
class ExampleApp(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.label = tk.Label(self, text="", width=10, font= ("Helvetica",72), background='yellow', fg = 'red')
self.label2 = tk.Label(self, text="", width=10, font=("Helvetica",72), background='yellow', fg = 'blue')
self.label.pack()
self.label2.pack()
self.intervals = [[30, "Slow"], [60, "Exercise 1"],
[30, "Slow"], [60, "Exercise 2"],
[30, "Slow"], [60, "Exercise 3"],
[30, "Slow"], [60, "Exercise 4"],
]
self.countdown()
def countdown(self):
(remaining, label) = self.intervals[0]
self.label.configure(text=remaining)
self.label2.configure(text=label)
remaining -= 1
if remaining < 0:
self.intervals.pop(0)
else:
self.intervals[0][0] = remaining
if len(self.intervals) > 0:
self.after(1000, self.countdown)
else:
self.label.configure(text="Done!")
if __name__ == "__main__":
app = ExampleApp()
app.title("Intense Workout")
app.geometry('550x550+200+200')
app.configure(background='yellow')
app.mainloop()
Upvotes: 1