How to keep a function going after different function has been called? - python

I believe my program is freezing after:
if pressed(win.getMouse(), startImage):
task = 'start'
timeFormat()
Basically, what I'm trying to do is when the mouse point is on stopImage the timer will stop, and when the mouse click is on lapTimer, it will reset. When I take out
timeFormat()
the program will run through the while and then break. My stop and start button work, but not my lap button. How can i make it NOT stop the program after the stop button is pressed? So that I can hit start again or reset?
def pressed(pt, image):
width = image.getWidth()
height = image.getHeight()
anchor = image.getAnchor()
x1 = (anchor.getX()) - (.5 * width)
x2 = (anchor.getX()) + (.5 * width)
y1 = (anchor.getY()) - (.5 * height)
y2 = (anchor.getY()) + (.5 * height)
return(x1 <= pt.getX() <= x2 and y1 <= pt.getY() <= y2)
def timeFormat():
sec = 0
minute = 0
hour = 0
timeDisplay = "{0:02d}:{1:02d}:{2:02d}".format(hour, minute, sec)
timer.setText(timeDisplay)
while task == 'start':
task = 'start'
time.sleep(1)
sec += 1
if sec == 60:
sec = 0
minute += 1
if minute == 60:
sec = 0
minute = 0
hour += 1
timeDisplay = "{0:02d}:{1:02d}:{2:02d}".format(hour, minute, sec)
timer.setText(timeDisplay)
check = win.checkMouse()
if check != None:
if pressed(check, stopImage):
task = 'stop'
print('asd')
if pressed(check, startImage):
task = 'start'
if pressed(check, lapImage):
sec = 0
minute = 0
hour = 0
task = 'stop
def main():
while not pressed(win.getMouse(), startImage):
if task == 'stop':
break
if task == 'reset':
sec = 0
minute = 0
hour = 0
break
continue
timeFormat()
main()

Your timeFormat function never returns, so the calling code can't continue.
Your main loop has the condition while sec < 60, but every time sec is incremented to 60, it gets reset to zero again. This means the loop will never end.
It's not clear to me when you expect it to end, so I can't necessarily tell you how to fix the issue, but generally it's a bad idea when writing an interactive program to have multiple event loops unless you have a well defined structure for switching between them.
You have a lot of loops, and when one of them is running, all the others will necessarily be stuck waiting. Try moving some of the logic from separate loops into other functions that can be called from a single main loop.

All I had to do was switch some if statements around.

Related

While function stuck on first block of if-elif-else

I'm trying to code a small pomodoro-timer, it uses a while loop with an if-elif-else statement to check which timer to start.
As expected it starts with the first if-block and then modifies the variable, I would expect it to go the elif-block after that, however it seems to be stuck in the if-block. And doesn't reiterate the entire while loop code.
How to overcome this?
import os
import time
pomodoro = ['Pomodoro', 1500]
short_break = ['Short Break', 300]
long_break = ['Long Break', 1800]
pomodori_count = 0
def countdown(time_frame):
duration = time_frame[1]
while duration:
os.system('clear')
mins, secs = divmod(duration, 60)
timer = '{:02d}:{:02d}'.format(mins, secs)
print(f"{time_frame[0]} | {timer}")
time.sleep(1)
duration -= 1
while True:
last = ""
if last != "Pomodoro":
countdown(pomodoro)
last = "Pomodoro"
pomodori_count += 1
elif pomodori_count % 4 != 0:
countdown(short_break)
last = "Short Break"
else:
countdown(long_break)
last = "Long Break"
So what is wrong with this code is that you reset the last value in each repeat of the while loop, so it never persists its state for the next cycle.
You should declare the variable before the while loop to fix this issue
last = ""
while True:
if last != "Pomodoro":
countdown(pomodoro)
last = "Pomodoro"
pomodori_count += 1
elif pomodori_count % 4 != 0:
countdown(short_break)
last = "Short Break"
else:
countdown(long_break)
last = "Long Break"

How can I check for a key press at any point during a loop?

I am trying to make a timer that counts down to 0, then starts counting up. I am using the time and keyboard modules.
The keyboard module from PyPi.
Everything works as expected, and I am able to press a button to close the program, but it only works at the beginning of each iteration. Is there a way for it to check for a key press at any point while the loop is running? Do I need to be using a different module?
This is my code:
import time
import keyboard
m = 2
s = 0
count_down = True
while True:
if keyboard.is_pressed('q'):
break
print(f"{m} minutes, {s} seconds")
if count_down:
if s == 0:
m -= 1
s = 60
s -= 1
elif not count_down:
s += 1
if s == 60:
m += 1
s = 0
if m == 0 and s == 0:
count_down = False
time.sleep(1)
Using callback is common approach in such case, here is solution:
import time
import keyboard
m = 2
s = 0
count_down = True
break_loop_flag = False
def handle_q_button():
print('q pressed')
global break_loop_flag
break_loop_flag = True
keyboard.add_hotkey('q', handle_q_button)
while True:
if break_loop_flag:
break
print(f"{m} minutes, {s} seconds")
if count_down:
if s == 0:
m -= 1q
s = 60
s -= 1
elif not count_down:
s += 1
if s == 60:
m += 1
s = 0
if m == 0 and s == 0:
count_down = False
time.sleep(1)
If you want to do any two things in parallel, independently of another, you need to consider using multiprocessing. However, even if you do, your loop will either still need to check if a key has been registered in the other process, or you need to terminate the process running the loop forcefully, which may result in unexpected outcomes.
However, in your case, since there are no side effects like files being written, this would work:
import time
import keyboard
from multiprocessing import Process
def print_loop():
m = 2
s = 0
count_down = True
while True:
print(f"{m} minutes, {s} seconds")
if count_down:
if s == 0:
m -= 1
s = 60
s -= 1
elif not count_down:
s += 1
if s == 60:
m += 1
s = 0
if m == 0 and s == 0:
count_down = False
time.sleep(1)
def main():
p = Process(target=print_loop)
p.start()
# this loop runs truly in parallel with the print loop, constantly checking
while True:
if keyboard.is_pressed('q'):
break
# force the print loop to stop immediately, without finishing the current iteration
p.kill()
if __name__ == '__main__':
main()

How to set time limit using python

I am trying to create a little game with python. I already set everything but I would like to set a time limit. I found something on the internet but it is not working with this project but it works with another project.
c.create_text(450, 20, text = 'Time', fill = 'red')
c.create_text(650, 20, text = 'Score', fill = 'red')
time_text = c.create_text(450, 20, text = 'Time', fill = 'red')
score_text = c.create_text(650, 20, text = 'Score', fill = 'red')
def print_score(score) :
c.itemconfig(score_text, text = str(score))
def print_time(time) :
c.itemconfig(time_text, text = str(time))
ENNEMY_CHANCE = 10
TIME_LIMIT = 30
SCORE_BONUS = 1000
score = 0
bonus = 0
end = time() + TIME_LIMIT
#Main
while True :
if randint(1, ENNEMY_CHANCE) == 1:
create_ennemy()
move_ennemies()
hide_ennemies()
score += ennemy_kill()
if(int(score/SCORE_BONUS)) > bonus:
bonus += 1
end += TIME_LIMIT
print_score(score)
print_time(int(end - time()))
window.update()
But I get this:
end = time() + TIME_LIMIT
TypeError: 'int' object is not callable
If you know an easier way to set a time limit that would be super.
Did you import time? I think you used the "time" name as an integer variable somewhere in your code and you have ambiguous code. Try this to get current time:
import time as time_module
now = time_module.time()
Try this
import time
start = time.time() #the variable that holds the starting time
elapsed = 0 #the variable that holds the number of seconds elapsed.
while elapsed < 30: #while less than 30 seconds have elapsed
elapsed = time.time() - start #update the time elapsed

How can I account for lost time in a while loop when using time.sleep

import time
def get_time():
global time_elapsed
time_elapsed = 0
time_elapsed = time.time() - last_time
return time_elapsed
def gear_encoder():
global gear_counter, run_counter,encoder_running, sensor_state,last_time
gear_counter = 0
run_counter = 0
encoder_running = False
sensor_state = False
encoder_running = True
while encoder_running:
last_time = time.time()
if run_counter >= 320:
print("END")
break
if sensor_state == True and gear_counter <= 5:
sensor_state = not sensor_state
gear_counter += 1
run_counter += 1
#print("State is " + str(sensor_state))
time.sleep((1.0/24) - get_time())
elif sensor_state == False and gear_counter <= 5:
sensor_state = not sensor_state
gear_counter += 1
run_counter += 1
#print("State is " + str(sensor_state))
time.sleep((1.0/24) - get_time())
elif sensor_state == True and gear_counter <= 8:
sensor_state = not sensor_state
gear_counter += 1
run_counter +=1
#print("State is " + str(sensor_state))
time.sleep((1.0/72) - get_time())
elif sensor_state == False and gear_counter <= 8:
sensor_state = not sensor_state
gear_counter += 1
run_counter +=1
#print("State is " + str(sensor_state))
time.sleep((1.0/72) - get_time())
else:
gear_counter = 0
start_time = time.time()
gear_encoder()
end_time = time.time() - start_time
print("The sensor changed states " + str(run_counter) + " times")
print(str(end_time))
So this is the code that I've got so far. If it runs this is it's output.
END
The sensor changed states 320 times
10.504526853561401
So what I attempted to set up was function called get_time() that will find the difference in time from when the variable last_time is called to when the actual function is called. The goal of this was to account for the time it takes to change the sensor_state and add to the counter variables in the sleep function.
You could do the math yourself but when this loops through 320 times all the time.sleeps that the program runs through add up to 10 seconds. I want the program to end in as close to 10 seconds as possible which is why I tried to account for the extra time with the get_time() function by subtracting the time it took to change sensor state and add to the counters.
My question to you all is, do you know of any methods that could help me lower this time drift? Was my technique to account for lost time even a valid approach? I would like to at some point add variables as arguments into time.sleep and probably lower the sleep to even smaller values than (1.0/72) seconds. Might multi threading be an option here? Any input would be appreciated.
The answer I'd give in code is pretty extensive. Let's see if I can get you on the path. You probably don't want to use sleep, because it blocks and everything becomes serial. That's important because you stated you want to exit in as close to 10 seconds as possible. That's fairly straightforward, if you don't have blocking calls going on. The other timers can be set up similarly. I show some examples below. Set up a timer to exit in 10 seconds. Note that the timer that is set for 11 seconds will not occur because the exit occurs before it triggers. This must be run as a script -- not interactively.
import sched, time, sys
def myExit():
# Do stuff here
sys.exit()
s = sched.scheduler(time.time, time.sleep)
# This causes the program to exit...
s.enter(10, 1, myExit, ())
s.enter(2.0/5, 2, print_answer, (1,))
s.enter(3.0/5, 2, print_answer, (2,))
s.enter(11, 2, print_answer, (3,))
s.run()

Pygame datetime troubles [duplicate]

This question already has answers here:
Python: pop from empty list
(5 answers)
Closed 3 years ago.
I was experimenting with some datetime code in python so I could do a time.sleep like function on one piece of code, while letting other code run.
Here is my code:
import datetime, pygame
pygame.init()
secondtick = pygame.time.Clock()
timestr = str(datetime.datetime.now().time())
timelist = list(timestr)
timex = 1
while timex <= 6:
timelist.pop(0)
timex += 1
timex2 = 1
while timex2 <= 7:
timelist.pop(2)
timex2 += 1
secondstr1 = str("".join(timelist))
while 1:
timestr = str(datetime.datetime.now().time())
timelist = list(timestr)
timex = 1
while timex <= 6:
timelist.pop(0)
timex += 1
timex2 = 1
while timex2 <= 7:
timelist.pop(2)
timex2 += 1
secondstr2 = str("".join(timelist))
x = 1
if int(secondstr2) - x == int(secondstr1):
print(x)
x += 1
and here is the result:
C:\Python32\python.exe "C:/Users/depia/PycharmProjects/testing/test.py"
Traceback (most recent call last):
File "C:/Users/depia/PycharmProjects/testing/test.py", line 31, in <module>
timelist.pop(2)
IndexError: pop index out of range
Process finished with exit code 1
If I add a time.sleep(1) after importing time right here:
-- code --
time.sleep(1)
secondstr2 = str("".join(timelist))
-- more code --
this is the output:
C:\Python32\python.exe "C:/Users/depia/PycharmProjects/testing/test.py"
1
then it never ends. It just stays like that forever. Can anyone help?
You can use pygame.time.get_ticks to control time.
To delay your event for 1 second (1000ms) first you set
end_time = pygame.time.get_ticks() + 1000
and later in loop you check
if pygame.time.get_ticks() >= end_time:
do_something()
or even (to repeat it every 1000ms)
if pygame.time.get_ticks() >= end_time:
do_something()
end_time = pygame.time.get_ticks() + 1000
#end_time = end_time + 1000
It is very popular method to control times for many different elements in the same loop.
Or you can use pygame.time.set_timer() to create own event every 1000ms.
First set
pygame.time.set_timer(pygame.USEREVENT+1, 1000)
and later in loop you check
for event in pygame.event.get():
if event.type == pygame.USEREVENT+1:
do_something()
It is useful if you have to do something periodicaly
BTW: use 0 to turn off event
pygame.time.set_timer(pygame.USEREVENT+1, 0)

Categories