Reputation: 11
I'm attempting to create a simple timer application in which the user presses a start button (or uses the keybind) and the clock continually updates until the user presses a stop button (or uses the keybind), but in trying to create this I have got stuck in an infinite loop.
I've tried creating a boolean flag in which True indicates to end the updating and used a while loop to check this, however the program ends up stuck in an infinite loop. This is all in python 3.x (specifically v3.6.7). In the code provided, I reduced it as far as I could whilst maintaining the error and context of the error. I also removed the keybinds I mentioned earlier as these are not part of the issue.
import tkinter as tk
class cubeTimer():
def __init__(self):
##Defines parts of timer
self.start_time = 0.0
self.end_time = 0.0
self.difference = 0.0
def get_time(self,num):
##Gets time since epoch
if num == 1:
self.start_time = time.time()
elif num == 2:
self.end_time = time.time()
def get_difference(self):
##Finds difference bwteen start and end times
self.difference = self.end_time - self.start_time
return self.difference
class cubeGUI():
def __init__(self):
##Instance variables for later use
self.num = 0
self.time_difference = 0
self.flag = False
##Creates instance of timer class
self.timer = cubeTimer()
##Creates GUI
self.root = tk.Tk()
##Label to show the solve time
self.time_label = tk.Label(text='-',height=5,width=10)
self.time_label.grid(row=1,columnspan=2,sticky=tk.W)
##Button to start timer
self.start_button = tk.Button(text='Start',height=5,width=10,command=self.start_process)
self.start_button.grid(row=2,column=0)
##Button to end timer, initialised as disabled
self.end_button = tk.Button(text='End',state=tk.DISABLED,height=5,width=10,command=self.end_process)
self.end_button.grid(row=2,column=1)
def start_process(self):
##Sets variable
self.num = 1
##Calls timer to get time
self.timer.get_time(self.num)
##Configures necessary buttons
self.start_button.configure(state=tk.DISABLED)
self.end_button.configure(state=tk.NORMAL)
while self.flag == False:
self.time_difference = self.timer.get_difference()
self.time_label.configure(text=self.time_difference)
time.sleep(0.1)
def end_process(self):
##Sets variable
self.num = 2
##Calls timer to get time
self.timer.get_time(self.num)
##Updates flag
self.flag = True
##Configures necessary button
self.end_button.configure(state=tk.DISABLED)
##Calls time difference
self.time_difference = self.timer.get_difference()
##Puts it on screen
self.time_label.configure(text=self.time_difference)
myTimer = cubeGUI()
I expected the program to update the time label every 0.1 seconds (or any given time period), but instead the program freezes as it encounters an infinite loop and becomes stuck.
Upvotes: 1
Views: 79
Reputation: 13729
You can't use a loop inside a GUI because it interferes with the GUI mainloop. Instead you have to structure your program to integrate into the mainloop. In tkinter, that's done with the after()
method. Here is your code fixed (as far as I can infer what you are trying to do), including a proper class:
import tkinter as tk
class CubeTimer(tk.Frame):
def __init__(self, master=None, **kwargs):
super().__init__(master, **kwargs)
self.timer = ' '
self.time_value = tk.IntVar()
##Label to show the solve time
time_label = tk.Label(self, textvariable=self.time_value,height=5,width=10)
time_label.grid(row=1,columnspan=2,sticky=tk.W)
##Button to start timer
self.start_button = tk.Button(self, text='Start',height=5,width=10,command=self.start_process)
self.start_button.grid(row=2,column=0)
##Button to end timer, initialised as disabled
self.end_button = tk.Button(self, text='End',state=tk.DISABLED,height=5,width=10,command=self.end_process)
self.end_button.grid(row=2,column=1)
def timer_tick(self):
self.time_value.set(self.time_value.get() + 1)
self.timer = self.after(1000, self.timer_tick) # schedule this method to be called again in 1,000 millisconds (1 second)
def start_process(self):
##Configures necessary buttons
self.start_button.configure(state=tk.DISABLED)
self.end_button.configure(state=tk.NORMAL)
self.timer_tick()
def end_process(self):
self.after_cancel(self.timer) # cancel the scheduled method call
##Configures necessary button
self.end_button.configure(state=tk.DISABLED)
self.start_button.configure(state=tk.NORMAL)
def main():
root = tk.Tk()
myTimer = CubeTimer(root)
myTimer.pack()
root.mainloop()
if __name__ == "__main__":
main()
Upvotes: 1