call function after certain time and kill on button press, tkinter - python

I have made an entry widget and it gets the number entered when they click OK (this becomes the number of seconds for function to recur(n)), I want to call the function every n seconds. When OK is clicked, I want a button to show on the screen that will stop the function from recurring. How can I do this?
This is what I have:
def ok_func():
global stop
stop = 1
timer_pop.destroy()
seconds = seconds_entry.get()
seconds = int(seconds)
stop_timer.grid()
while stop == 1:
stop_timer.config(highlightbackground=mycolor)
background()
time.sleep(seconds)
This is what I have for the stop timer button:
def stopTimer():
global stop
stop = 0
stop_timer.grid_forget()
Thanks
edit:
global counter
counter = 0
def ok_func():
global stop_timer
print('function: "ok" is running now.')
global counter
counter += 1
def stopTimer():
global recur
stop_timer.destroy()
timer_pop.after_cancel(recur)
try:
if counter == 1:
global time
time = int(seconds_entry.get())
timer_pop.destroy()
stop_timer = Button(app, text="Stop Timer", command=stopTimer)
stop_timer.grid(row=0, column=6, padx=10)
#stop_timer.config(highlightbackground=ok_func)
global recur
print ('function will start again in', time, 'seconds')
recur = app.after(1000*time, background)
else:
print ('function will start again in', time, 'seconds')
recur = app.after(1000*time, background)
#stop_timer.config(highlightbackground=mycolor)
except ValueError:
counter = 0
print("thats not a number")
I tried what you said but still not working. The color only changes once, then stops. Also, I would like the stoptimer button to change background with the background but it doesn't work. Thanks for your help.

Here is a complete example which does what you want it to (i think.)
a recurring function is created and you choose how often it recurs, then you can kill it with a button press (using after_cancel so program will still run, but wont do anything.).
from tkinter import *
root = Tk()
global counter
counter = 0
def ok():
print('function: "ok" is running now.')
global counter
counter += 1
def stop():
global recur
label.destroy()
stop_button.destroy()
root.after_cancel(recur)
try:
if counter == 1:
global time
time = int(entry.get())
label.config(text = 'your only option now is to stop the function')
entry.destroy()
ok_button.destroy()
stop_button = Button(text = 'stop', command = stop)
stop_button.pack()
global recur
print ('function will start again in', time, 'seconds')
recur = root.after(1000*time, ok)
else:
print ('function will start again in', time, 'seconds')
recur = root.after(1000*time, ok)
except ValueError:
counter = 0
print('thats not a number')
label = Label(root, text = 'pick a number of seconds for the function to recur in')
label.pack()
entry = Entry(root)
entry.pack()
ok_button = Button(root, text = 'Ok', command = ok)
ok_button.pack()
root.title('cool recurring function')
root.mainloop()
hope that was what you wanted, if not yell out (and tell me what you did want)!

Related

How to make a speedrun timer stay to the front

I made an in game timer for Minecraft to use while speedrunning and it works great but the one problem is that when I make Minecraft fill my whole screen NOT FULLSCREEN just cover it the timer disappears.
I knew this would happen and I am wondering if this is possible to fix and make the pygame window go to the front even if it is blocked by an app that you are currently using.
You can do this with Tkinter:
This way, you can make a timer:
Always put to front
Transparent
Furthermore, tkinter is in the Standard library.
You can use this code:
from tkinter import *
from threading import Thread
from time import time
tk = Tk()
tk.title('Timer')
tk.wm_attributes('-topmost', 1) # put the window to front
pause = True
start = time()
time_when_paused = time() # time displayed when in pause
def restart(): # restart to 0
global pause, start
pause = False
start = time()
def toggle_pause():
global pause, start, time_when_paused
pause = not pause
if pause:
time_when_paused = time() # update the time displayed
else:
start += time() - time_when_paused # forget the time passed in pause
def timer():
while True:
if pause:
label['text'] = '%.2f' %(time_when_paused - start) # %.2f for 2 decimals
label['fg'] = 'orange'
else:
label['text'] = '%.2f' %(time() - start)
label['fg'] = 'green'
label = Label(tk, '', font=('Helvetica', 30), fg='orange')
label.grid(columnspan=2) # display the timer
# buttons
restart_button = Button(tk, text='Restart', width=20, command=restart)
restart_button.grid(padx=5, pady=5)
pause_button = Button(tk, text='Pause', width=20, command=toggle_pause)
pause_button.grid(padx=(0, 5), column=1, row=1)
timer_thread = Thread(target=timer)
timer_thread.start() # put in a thread because of...
tk.mainloop() # ...this which acts like "while window is not closed"

Python Program Breaks After 1 Run

Thanks so much for Helping, It's fixed now thanks to you guys.
The problem was after I got my cps count the program delayed and froze. It stopped showing the cps.
I can't find out why this happens or how to fix it. The program is a cps counter, it works after 1 try then it breaks and freezes if I use it a second time.
I also have no idea where the code breaks, thank you so much.
Here is the code:
import threading
from tkinter import *
import time
clicks = 0
cps = 0
start = True
wn = Tk()
wn.title("Cps Counter")
wn.geometry("400x300")
def cps5():
global start
global cps
global clicks
global t1
start = False
time.sleep(5)
cps = (clicks / 5)
clicks = 0
CpsButton.config(text=clicks)
CpsAmount.config(text=cps)
start = True
time.sleep(.1
t1 = threading.Thread(target=cps5)
t1.start()
def AddClicks():
global clicks
global start
clicks += 1
CpsButton.config(text=clicks)
if start == True:
cps5()
CpsButton = Button(wn, text=clicks, command=AddClicks, pady=15, padx=15)
CpsAmount = Label(wn, text=cps, pady=15, padx=15)
CpsAmount.pack()
CpsButton.pack()
wn.mainloop()
import threading
from tkinter import *
import time
clicks = 0
cps = 0
start = True
wn = Tk()
wn.title("Cps Counter")
wn.geometry("400x300")
clicks = 0
def cps5():
global start
global cps
global clicks
global t1
start = False
CpsButton.config(text=clicks)
start = True
def AddClicks():
global clicks
global start
clicks += 1
CpsButton.config(text=clicks)
if start == True:
cps5()
CpsButton = Button(wn, text=clicks, command=AddClicks, pady=15, padx=15)
CpsAmount = Label(wn, text=cps, pady=15, padx=15)
CpsAmount.pack()
CpsButton.pack()
def Timer():
global CpsAmount, cps, clicks
for i in range(0, 5):
time.sleep(1)
cps = (clicks / 5)
CpsAmount.config(text=cps)
clicks = 0
Timer()
t1 = threading.Thread(target=cps5)
t1.start()
t2 = threading.Thread(target=Timer)
t2.start()
wn.mainloop()
I created a second thread for the counter, because time.sleep freezes the program and caused trouble.

call a function inside a function in tkinter

when calling rest function from button, then start function is called and prints values continues every second But when I call again rest function the start function call again but this time start function print values in 2x speed and so on.
But I don't want to print value in 2x speed. I am making a small project where I face this type of problem so that is why I write this small code. Please solve my problem
import tkinter as tk
window = tk.Tk()
window.geometry('400x400')
i = 0
def start():
global i
text_label .config(text=i)
i += 1
text_label .after(1000, start)
def rest():
global i
i=0
start()
text_label = tk.Label(window, text="start")
text_label .pack()
tk.Button(window, text="rest", command=rest).pack()
window.mainloop()
What is happening is that every time you call reset, a new callback is launched that will call start indefinitely every 100ms. Every callback being independent, and having no knowledge of the others, this results in a series of callbacks each calling start on their own time, every 100 ms.
To avoid this "snowballing", you need to cancel the previous callbacks in order to reset properly. You do this by keeping a reference on the callback, and calling tk.after_cancel(callback_id) in reset.
Like this:
import tkinter as tk
def start():
global i, callback_id
text_label.config(text=i)
i += 1
callback_id = text_label.after(1000, start)
def reset():
global i, callback_id
i = 0
if callback_id is not None:
text_label.after_cancel(callback_id)
callback_id = None
start()
window = tk.Tk()
window.geometry('400x400')
text_label = tk.Label(window, text="start")
text_label.pack()
callback_id, i = None, 0
tk.Button(window, text="reset", command=reset).pack()
window.mainloop()

How to stop this after function in python tkinter

I am trying to make a Stopwatch program and whenever i run it pressing the button , the function def watch() keeps executing itself and i cant stop it when needed.
is there any way to stop the execution of def watch() function after pressing the button?
Thanking you...
from tkinter import *
root = Tk()
tog = 0
hour = 0
mins = 0
sec = 0
def toggle():
global tog
tog = tog + 1
if tog == 1:
watch()
elif tog == 2:
stop()
tog = 0
def stop():
donothing = 0
def watch():
global sec
global hour
global mins
sec = sec + 1
l1.config(text=sec)
l1.after(1000,watch)
l1 = Label(root)
l1.pack()
Button(root,text="Start",command= lambda: toggle()).pack()
root.mainloop()
You should keep a reference to the after call, and cancel the callback when toggle is False. You can avoid ugly global declarations by using tkinter variables that are objects whose value can be read or set.
import tkinter as tk
def toggle_on_off():
toggle.set(not toggle.get())
if toggle.get():
watch()
def watch():
count_seconds.set(count_seconds.get() + 1)
if toggle.get():
_callback_id.set(root.after(1000, watch))
else:
root.after_cancel(_callback_id.get())
root = tk.Tk()
count_seconds = tk.IntVar(root)
count_seconds.set(0)
toggle = tk.BooleanVar(root)
toggle.set(False)
Button(root,text="Start",command=toggle_on_off).pack()
label = tk.Label(root, textvariable=count_seconds)
label.pack()
_callback_id = tk.StringVar(root)
_callback_id.set(None)
root.mainloop()
[Edit]
The same code with globals is like this:
import tkinter as tk
def toggle_on_off():
global toggle
toggle = not toggle
if toggle:
watch()
def watch():
global count_seconds, _callback_id
count_seconds += 1
label.configure(text=str(count_seconds))
if toggle:
_callback_id = root.after(1000, watch)
else:
root.after_cancel(_callback_id)
root = tk.Tk()
count_seconds = 0
toggle = False
Button(root,text="Start",command=toggle_on_off).pack()
label = tk.Label(root, text=str(count_seconds))
label.pack()
_callback_id = None
root.mainloop()
You can add a global variable , for eaxmple "exit",
and add an if statement before l1.after(1000,watch)
def toggle():
global tog, exit
exit = False
tog = tog + 1
if tog == 1:
watch()
elif tog == 2:
stop()
tog = 0
def watch():
global sec
global hour
global mins
global exit
sec = sec + 1
l1.config(text=sec)
if not exit:
l1.after(1000,watch)
in stop(), you can write
def stop():
global exit
exit = True

Count time intervals (secs) between 2 button clicks

I have a programm in Python with a simple GUI that simulates a queue management system. When i press the Button "Next Customer" it displays the next queue number. Now i want to count the time intervals between the 2 clicks (on the button "Next Customer") so to track the service time needed. How is this possible? The code is the following.
import time
import random
from Tkinter import *
def PrintNumber():
global j, label
j+=1
label.config(text=str(j))
print j
t = (time.strftime("%H:%M:%S"))
d = time.strftime("%d/%m/%Y")
return
j=0
mgui=Tk()
mgui.geometry('200x200')
mgui.title('Queue System')
st = Button(mgui, text="Next Customer", command = PrintNumber)
st.pack()
label = Label(mgui, text=str(j))
label.pack()
mgui.mainloop()
This is my lazy solution:
import time
import random
from Tkinter import *
class GetClicktime():
def __init__(self):
self.j=0
self.t=[]
self.mgui=Tk()
self.mgui.geometry('200x200')
self.mgui.title('Queue System')
self.st = Button(self.mgui, text="Next Customer", command = self.PrintNumber)
self.st.pack()
#self.st.bind('<Button-1>',callback)
self.label = Label(self.mgui, text=str(self.j))
self.label.pack()
self.mgui.mainloop()
def PrintNumber(self):
self.j+=1
self.label.config(text=str(self.j))
print self.j
t = (time.strftime("%H:%M:%S"))
d = time.strftime("%d/%m/%Y")
self.t.append(int(t.replace(':','')))
print self.t
if self.j >2:
print 'the time between clicks is:',self.t[self.j-1]-self.t[self.j-2],'seconds'
print t,d
return
if __name__ == "__main__":
GetClicktime()
you can avoid writing a class, but this does what you need to.
If you need some docs on classes i recommmend: https://www.youtube.com/watch?v=trOZBgZ8F_c#start=0:00;end=13:27;cycles=-1;autoreplay=false;showoptions=false
you could begin the timer after the first button pressed and end it after the second pressed. You could add a condition to determining weather it is the first press.
if start:
elapsed = (time.clock() - start)
print (elapsed)
start = time.clock()

Categories

Resources