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.
Related
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"
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
I'm using trying to use python with an ultrasonic sensor to measure distance, and then update a tkinter label with the distance value every second. However, I'm having problems; it will run for a while, anything from a couple of seconds up to a few minutes, then freeze.
Here is my code:
from tkinter import *
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)
GPIO_TRIGGER_X = 4
GPIO_ECHO_X = 27
GPIO.setup(GPIO_TRIGGER_X, GPIO.OUT)
GPIO.setup(GPIO_ECHO_X, GPIO.IN)
def distanceX():
GPIO.output(GPIO_TRIGGER_X, True)
time.sleep(0.0001)
GPIO.output(GPIO_TRIGGER_X, False)
StartTime = time.time()
StopTime = time.time()
while GPIO.input(GPIO_ECHO_X) == 0:
StartTime = time.time()
while GPIO.input(GPIO_ECHO_X) == 1:
StopTime = time.time()
TimeElapsed = StopTime - StartTime
distance = (TimeElapsed * 34300) / 2
return distance
def updateDistance():
dX = distanceX()
print(dX)
lengthValue.configure(text=dX)
root.after(1000, updateDistance)
root = Tk()
root.geometry("200x100")
root.tk_setPalette(background="white", foreground="black")
lengthName = Label(root, text = "Length:")
lengthValue = Label(root, text="start")
lengthName.grid(row=1, column=1)
lengthValue.grid(row=1, column=2)
updateDistance()
root.mainloop()
I have tried running distanceX() alone in a separate script just printing out the values, that works fine. I've also tried the running the script without distanceX() like this:
dX = 0
def updateDistance():
global dX
print(dX)
lengthValue.configure(text=dX)
dX += 1
root.after(1000, updateDistance)
..and that also works fine.
Any ideas?
Apologies in advance if I've left any needed info out, this is my first go at python and tkinter...
Tkinter is single threaded. Your while loop in function distanceX blocks the main thread until it receives a True value and continues with the rest of the function. That's why you are experiencing freezes.
Try run the below:
from tkinter import *
import time
root = Tk()
flag = True
def something():
global flag
while flag:
print ("Hello World")
time.sleep(1)
def set_flag():
global flag
flag = False
something()
root.after(2000,set_flag)
root.mainloop()
And you will see your Tk window won't even pop up due to While loop blocking the main thread.
To solve this, you need to thread your distanceX() function. Something like:
from tkinter import *
import threading, time
root = Tk()
flag = True
def something():
global flag
while flag:
print ("Hello world")
time.sleep(1)
def set_flag():
global flag
flag = False
t = threading.Thread(target=something)
t.start()
root.after(2000,set_flag)
root.mainloop()
You can read more about threading in here.
Turns out the problem was in fact the two while loops in distanceX(). Added a timeout to both and all is well. Working code:
from tkinter import *
import RPi.GPIO as GPIO
import threading, time
GPIO.setmode(GPIO.BCM)
GPIO_TRIGGER_X = 4
GPIO_ECHO_X = 27
GPIO.setup(GPIO_TRIGGER_X, GPIO.OUT)
GPIO.setup(GPIO_ECHO_X, GPIO.IN)
def distanceX():
while True:
timeout = time.time() + 0.1
GPIO.output(GPIO_TRIGGER_X, True)
time.sleep(0.0001)
GPIO.output(GPIO_TRIGGER_X, False)
StartTime = time.time()
StopTime = time.time()
while GPIO.input(GPIO_ECHO_X) == 0:
StartTime = time.time()
if time.time() > timeout:
break
while GPIO.input(GPIO_ECHO_X) == 1:
StopTime = time.time()
if time.time() > timeout:
break
TimeElapsed = StopTime - StartTime
distance = (TimeElapsed * 34300) / 2
print(distance)
lengthValue.configure(text=distance)
time.sleep(1)
def check():
print("All good")
root = Tk()
root.geometry("200x100")
root.tk_setPalette(background="white", foreground="black")
lengthName = Label(root, text = "Length:")
lengthValue = Label(root, text="start")
button = Button(root, text="Check", command=check)
lengthName.grid(row=1, column=1)
lengthValue.grid(row=1, column=2)
button.grid(row=2, column=1)
t1 = threading.Thread(target=distanceX)
t1.start()
root.mainloop()
I need to make this clock open only after pressing a key, lets say "t". Now it opens immediately after running it.
import tkinter as tk
def update_timeText():
if (state):
global timer
timer[2] += 1
if (timer[2] >= 100):
timer[2] = 0
timer[1] += 1
if (timer[1] >= 60):
timer[0] += 1
timer[1] = 0
timeString = pattern.format(timer[0], timer[1], timer[2])
timeText.configure(text=timeString)
root.after(10, update_timeText)
def start():
global state
state=True
state = False
root = tk.Tk()
root.wm_title('Simple Kitchen Timer Example')
timer = [0, 0, 0]
pattern = '{0:02d}:{1:02d}:{2:02d}'
timeText = tk.Label(root, text="00:00:00", font=("Helvetica", 50))
timeText.pack()
startButton = tk.Button(root, text='Start', command=start)
startButton.pack()
update_timeText()
root.mainloop()
It is in another program so as I have my graphics window I will press "t" and the clock will open.
Keyboard is a python module that can detect keystrokes. Install it by doing this command.
pip install keyboard
Now you can do this.
while True:
try:
if keyboard.is_pressed('t'):
state = True
elif(state != True):
pass
except:
state = False
break #a key other than t the loop will break
I would recommend you to organize the code little bit, like class structure. One possible implementation would be like that:
import tkinter as tk
TIMER = [0, 0, 0]
PATTERN = '{0:02d}:{1:02d}:{2:02d}'
class Timer:
def __init__(self, master):
#I init some variables
self.master = master
self.state = False
self.startButton = tk.Button(root, text='Start', command=lambda: self.start())
self.startButton.pack()
self.timeText = tk.Label(root, text="00:00:00", font=("Helvetica", 50))
self.timeText.pack()
def start(self):
self.state = True
self.update_timeText()
def update_timeText(self):
if (self.state):
global TIMER
TIMER[2] += 1
if (TIMER[2] >= 100):
TIMER[2] = 0
TIMER[1] += 1
if (TIMER[1] >= 60):
TIMER[0] += 1
TIMER[1] = 0
timeString = PATTERN.format(TIMER[0], TIMER[1], TIMER[2])
self.timeText.configure(text=timeString)
self.master.after(10, self.update_timeText)
if __name__ == '__main__':
root = tk.Tk()
root.geometry("900x600")
root.title("Simple Kitchen Timer Example")
graph_class_object = Timer(master=root)
root.mainloop()
So clock will start when you click to button. If you want to start the clock by pressing "t" in keyboard, you need to bind that key to your function.
You can also add functionality if you want to stop the clock when you click to the button one more time.
EDIT:
if you also want to start to display the clock by clicking the button, you can move the code for initializing the label in to start function.
def start(self):
self.state = True
self.timeText = tk.Label(root, text="00:00:00", font=("Helvetica", 50))
self.timeText.pack()
self.update_timeText()
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)!