Reputation: 439
I have a button that executes a function (in tkinter). Let's say it adds money in a video game. So when you press that button, you get 100 dollars. However, I only want my user to be able to add 100 dollars once per minute. Is there a way to only allow a function to be called once a minute? (maybe with the time module or something?)
The most i know about managing time in a function is this, I would like to do something along these lines:
def add_money():
money = money + 100
app.after(5000, add_money)
I know that this function would obviously not get what i want. Is there a way to implement it so that if you clicked the button and a minute had not passed, the program would do nothing?
Thanks in advance
Upvotes: 1
Views: 476
Reputation: 385970
In the add_money function, disable the "add money" button, and then schedule it to be re-enabled after one minute:
def add_money():
<do the real work here>
add_money_button.configure(state="disabled")
root.after(60000, lambda: add_money_button.configure(state="normal"))
If your app has multiple ways to add money, such as a menu item, a button, and an accelerator key, create a function that enables or disables all of those items, then call that function via after
.
Upvotes: 1
Reputation: 21368
I'd actually likely implement this as a decorator as it sounds like something reusable. The sample below allows you to reuse guarded
on any function you want, specifying the timeout (in seconds) for each function you use the decorator on:
import time
from functools import wraps
_guards = {}
def guarded(tm):
def wrapper(fn):
_guards[fn] = {'timeout': tm}
@wraps(fn)
def inner(*args, **kwargs):
t = time.time()
if 'last' not in _guards[fn] or \
t - _guards[fn]['last'] > _guards[fn]['timeout']:
_guards[fn]['last'] = t
fn(*args, **kwargs)
return inner
return wrapper
money = 0
@guarded(2)
def add_money():
global money
money += 100
print money
Here, add_money
is only allowed after a 2 second timeout:
In [2]: add_money()
100
In [3]: add_money()
In [4]: add_money()
200
In [5]: add_money()
In [6]: add_money()
In [7]: add_money()
In [8]: add_money()
300
Yes, there are arguments for not using a global dict to track this stuff (bad when running multithreaded) and to use threading.local
instead, but that's kinda outside the scope of this answer.
Upvotes: 1
Reputation: 531165
Just track time yourself, and do nothing if too little time has elapsed.
def add_money():
curr_time = int(time.time())
if curr_time - app.last_time > 60:
app.last_time = curr_time
money = money + 100
This way, the function can be called as often as the user likes, but it will only do what he wants once a minute.
Upvotes: 1