'Is there a way to make a function run after a specified amount of time in Python without the after method?
I am trying to create a simple program that tracks a user's clicks per second in Tkinter, but I have no idea how to make the program wait without freezing the program using the after method. The problem is that I need to log the high score after the time finishes, but using this method, the score logs before the click counter goes up. Here is my code:
from tkinter import *
import time
root = Tk()
root.geometry('600x410')
screen = Canvas(root)
h = 6 #button height
w = 12 #button width
c = 0 #counts amount of times clicked
start_btn = 0 #logs clicks of the start button
high_score = 0 #logs the highest score
time = 0
def count_hs():
high_score = c
def remove_time():
global time
time -= 1
def countdown(n):
for i in range(n):
time = n
root.after(1000, remove_time())
#alternatively i tried this:
#time.sleep(1)
#remove_time()
if time <= 0:
b["text"] = "Test done."
break
def start_test():
global start_btn
b["text"] = "Click to begin."
start_btn += 1
print("start button: " + str(start_btn))
def button_click():
global start_btn
global c
c+=1
print("click counter: " + str(c))
#resets the amount of clicks on the large button when the start button is pressed
if c >= 1 and start_btn >= 1:
print("test1")
c = 1
start_btn = 0
if b["text"] == "Click to begin.":
print("test2")
b["text"] = "Click!"
countdown(6)
count_hs()
print("hs: " +str(high_score))
#primary button
b = Button(root, text=" ", font=("Arial", 40), height = h, width = w, command = lambda: button_click())
b.grid(row=0, column=0)
#start button
start = Button(root, text="Start.", command = lambda: start_test())
start.grid(row=0, column=1)
root.mainloop()
Solution 1:[1]
Give it a try
from tkinter import *
root = Tk()
root.geometry('600x410')
screen = Canvas(root)
h = 6 # button height
w = 12 # button width
c = 0 # counts amount of times clicked
start_btn = 0 # logs clicks of the start button
high_score = 0 # logs the highest score
time = 0
def count_hs():
global high_score
if c > high_score:
high_score = c
return high_score
def remove_time():
global time
time -= 1
if time > 0:
root.after(1000, remove_time)
else:
show_score()
def start_test():
global start_btn
global c
global time
b["text"] = "Click to begin."
start_btn += 1
print("start button: " + str(start_btn))
# Reset your timer and counter
time = 6
c = 0
def button_click(*args):
global start_btn
global c
# resets the amount of clicks on the large button when the start button is pressed
if c == 0 and start_btn >= 1:
start_btn = 0
b["text"] = "Click!"
root.after(1000, remove_time)
print("hs: " + str(high_score))
else:
c += 1
print("click counter: " + str(c))
def show_score():
global c
score_label.configure(text=str(c))
high_score_label.configure(text=str(count_hs()))
c = 0
b['text'] = ""
# primary button
b = Button(root, text="", font=("Arial", 40), height=h, width=w, command=button_click)
b.grid(row=0, column=0, rowspan=5)
# start button
start = Button(root, text="Start.", command=lambda: start_test())
start.grid(row=0, column=1)
Label(root, text="Your score").grid(row=1, column=1)
score_label = Label(root, text="")
score_label.grid(row=2, column=1)
Label(root, text="High score").grid(row=3, column=1)
high_score_label = Label(root, text="")
high_score_label.grid(row=4, column=1)
root.mainloop()
Few changes:
- In
count_hsI assume you would update the highscore only if current score beats it. - You can use
remove_timeas a timer by making it calling itself untiltime <= 0, in which case you should end your game. - I've used the
startbutton as a resetter, so that when it is clicked it will resetcandtime. - On
button_clickyou can now only bother with updatingc(and change text at the beginning). - Finally I've added few labels to show the final results, both current and high scores.
Few suggestions to move on:
- Instead of
globalvariables you could create a class for the app, it should make it easier for you to exchange info and avoid subtle errors. - You could improve the layout, especially for the newly added labels.
- You could make your original timer a parameter (currently, it is set within
start_test). - Instead of importing
from tkinter import *, I'd suggest you to do something likeimport tkinter as tkorfrom tkinter import ...since it increases readability and reduces the sources of errors.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | ALai |
