I'm working on an irl minigame where you get materials every 5 minutes.
To monitor this i wanted to write a simple python script.
But now there is a little roadblok,
how do you make a loop that does something every x minutes, while still running other keyboard inputs without it disrupting the loop?
Here's a fairly simple example of using a threading.Timer. It displays the current time every 5 seconds while responding to user input.
This code will run in any terminal that supports ANSI / VT100 Terminal Control Escape Sequences.
#!/usr/bin/env python3
''' Scrolling Timer
Use a threading Timer loop to display the current time
while processing user input
See https://stackoverflow.com/q/45130837/4014959
Written by PM 2Ring 2017.07.18
'''
import readline
from time import ctime
from threading import Timer
# Some ANSI/VT100 Terminal Control Escape Sequences
CSI = '\x1b['
CLEAR = CSI + '2J'
CLEAR_LINE = CSI + '2K'
SAVE_CURSOR = CSI + 's'
UNSAVE_CURSOR = CSI + 'u'
GOTO_LINE = CSI + '%d;0H'
def emit(*args):
print(*args, sep='', end='', flush=True)
# Show the current time in the top line using a Timer thread loop
def show_time(interval):
global timer
emit(SAVE_CURSOR, GOTO_LINE % 1, CLEAR_LINE, ctime(), UNSAVE_CURSOR)
timer = Timer(interval, show_time, (interval,))
timer.start()
# Set up scrolling, leaving the top line fixed
emit(CLEAR, CSI + '2;r', GOTO_LINE % 2)
# Start the timer loop
show_time(interval=5)
try:
while True:
# Get user input and print it in upper case
print(input('> ').upper())
except KeyboardInterrupt:
timer.cancel()
# Cancel scrolling
emit('\n', SAVE_CURSOR, CSI + '0;0r', UNSAVE_CURSOR)
You need to send a KeyboardInterrupt, that is, hit CtrlC to stop this program,
Maybe a timer will be helpful for your task. I recommend you to check this link: https://docs.python.org/2.4/lib/timer-objects.html. While the timer is counting you are able to do other tasks and when the time is up, you can attach a function to the timer to do something. Timers from this library inherits from Threads
Related
I want to make a program that uses modal operators to continue printing ("test") every 0.01 seconds in Blender's Python.
I also want to exit when I press the Esc key.
What can I do?
I wrote and executed the following code, but Blender freezes. Using a modal operator seems to be able to avoid freezing, but I wasn't sure how to use it.
import time
import threading
#A function that keeps executing print ("test")
def worker():
while True:
print("test")
def schedule(interval, f, wait=True):
base_time = time.time()
next_time = 0
while True:
t = threading.Thread(target=f)
t.start()
if wait:
t.join()
next_time = ((base_time - time.time()) % interval) or interval
time.sleep(next_time)
#Execute worker function every 0.01 second
schedule(0.01, worker, False)
In blenders text editor you will find a python template called operator_modal_timer.py that works the way you want.
The first call to the operator is the execute() method, where you create the timer with wm.event_timer_add. Then in the modal() method you respond to the timer events or cancel the operator if you get an esc key event.
If you put the operator in an addon, you can have it enabled every time you start blender.
My timer won't work properly, since it keeps printing forever, not what I want.
I've already tried re-organizing the script in many ways, but the result is always the same.
import time
CommandInput = input()
#execution [uptime]
def uptime(y):
while 1 == 1:
if (CommandInput == "uptime"):
print(y, " seconds")
y = y + 1
time.sleep(1)
uptime(9)
I wanted to make some sort of "background timer" that kept running from when the script was executed up to when it was closed, and if I typed a certain line in the input it would show the current number it is in. The problem is that it keeps printing the timer forever, for every single number it counts. I wanted to do a one-time thing, where you could wait as much as you want and type the input, which would show the number the timer is in.
Your current program has to wait for input() to finish. The compiler does not move past the second line until the user hits enter. Thus the functions starts once the input is finished.
This timer could be done several way, such as threading or timers. There are some examples of that here and here. For threading, you need one process for user inputs and one for timers. But the better and easier way is to to use a timer and store the current time. I believe the following code is somewhat similar to what you want:
import time
start_time = time.time()
def get_time():
current_time = time.time()
total = current_time - start_time
return total
while True:
CommandInput = input()
if CommandInput == "uptime":
y = get_time()
print(str(round(y)) + " seconds")
The variable start_time records the current time at the start. time.time() gets the current time in seconds on the computer. The get_time function is called after an input and sees how much time has pasted by subtracting the current time minus the start time. This way the you do not need multiple loops.
The while True loops just waits for the user input and then prints the time. This then repeats until the program is exited.
To write a script like that you would need to look into a module called asyncio (https://docs.python.org/3/library/asyncio.html), which would allow you to run multiple things at the same time.
Here is a asyncio hello world:
import asyncio
async def main():
print('Hello ...')
await asyncio.sleep(1)
print('... World!')
# Python 3.7+
asyncio.run(main())
I'm looking to capture single USB keyboard events within a "while True" loop which includes a timer function as well. Evdev is close to what I need but it's device.read_loop does not allow for inclusion of a clock function - it's a closed loop. Any ideas as to how to capture a single USB keyboard event which I can control when it is checked? I'm using Python 3.4 so asyncio is not an option. Thank you.
Threading will help you here. As Python Module of the Week (PyMOTW) says:
Using threads allows a program to run multiple operations concurrently
in the same process space.
In your case you can still read the keyboard input in a blocking loop in its own thread and let the sleep function check the time in another thread without getting blocked by the read_loop of evdev. Just set the radio_sleep_time to the amount of seconds you want to wait until the radio sleeps (you can use minutes and radio_sleep_time = 4 * 60 instead to get 4 minutes).
from time import time
from threading import Thread
from evdev import *
radio_sleep_time = 4 # sleep time for radio in seconds
device = InputDevice('/dev/input/event3') # pick the right keyboard you want to use
def read_kb():
for event in device.read_loop():
# only use key events AND only key down can be changed depending on your use case.
if event.type == ecodes.EV_KEY and event.value == 1:
keyevent = categorize(event) # just used here to have something nice to print
print(keyevent) # print key pressed event
def wait_loop():
pass # whatever radio is doing when its waiting to sleep if anything.
class Time1(Thread):
def run(self):
while True:
read_kb()
class Time2(Thread):
def run(self):
t0 = time() # starting time
# time() (current time) - t0 (starting time) gives us the time elapsed since starting
while not time() - t0 > radio_sleep_time: # loop until time passed is greater than sleep_time
wait_loop() # do sleep stuff
print(time() - t0, ">", radio_sleep_time)
print("SLEEP")
# sleep radio here
# but continue to listen to keyboard
Time1().start()
Time2().start()
I have been searching and searching on how to figure out how to make an input or something go into a while loop. As in, the input() command won't stop my stopwatch. I have tried tkinter, pygame, and a couple other methods, but they just didn't work. If anyone can help me out, I would prefer something small and simple, if that's even possible. And to be specific on what I want to learn to do, is basically allowing, when any key is pressed, for it to instantly stop (preferably without hitting enter). Thanks, saddlepiggy!
Here is what I have so far, with nothing to activate the stopping:
#Setup (Variables and stuff)
hours = 0
minutes = 0
seconds = 0
import time
#Main Part of Code
print("Welcome to PyWatch, a stopwatch coded in Python!")
print("Press any key to start the stopwatch.")
print("Then, press any key to stop it!")
start = input("")
while hours < 48:
seconds = seconds + 1
time.sleep(1)
print(hours, "hours,", minutes, "minutes,", seconds, "seconds")
#If Statements for getting seconds/minutes/hours
if (seconds == 60):
minutes = minutes + 1
seconds = seconds - 60
if (minutes == 60):
hours =hours + 1
minutes = minutes - 60
Threading is what you want.
Create a second thread that waits for the input while your first thread handles your stopwatch code. Behold:
import threading, sys
def halt():
raw_input()
threading.Thread(target=halt).start()
while hours < 48 and threading.active_count() > 1:
seconds = seconds + 1
time.sleep(1)
# copy and past what you had before
Allow me to elaborate on what's happening: Thus far, all of the code you've written has been single threaded. This means only one line of code is executed at a time, there's only one thread of execution. Consequentially, your script can't multitask, it can't wait for input and print the time at the same time.
So when this line is evaluated
threading.Thread(target=halt).start()
The main thread creates a second thread of execution. Meanwhile, the main thread goes on and enters the while loop. The target parameter is the entry point of the thread, it's the starting point. It's analogous to if __name__ == "__main__:" for the main thread. Just as the main thread terminates when it reaches the end of if __name__ == "__main__:", our second thread will terminate once it reaches the end of halt().
The threading.active_count function tells you how many threads in are current in execution.
You can't do that in Python. You are asking for a keyboard event. Keyboard events are shipped with a GUI. This thread explains pretty much everything: QKeyPress event in PyQt
Or use an external application for your OS that can append output to a file that is read by your Python program in a loop. When a certain event is detected you can perform some actions. For Linux this tread explains: https://superuser.com/questions/248517/show-keys-pressed-in-linux
I'm trying to create a program that runs in a similar format to the game show Countdown.
I have found various ways to create a timer, most successfully with the time.sleep command and a while loop.
However, the user needs to be able to input a word whilst the timer is going on, otherwise the user could take as long as they want to think of their word after the timer has stopped. Once the timer has stopped, whatever the user has typed in should be taken as their word. I haven't found any kind of solution for this yet as python runs sequentially so it's difficult to have a timer and an input at the same time.
This worked for me previously... Uses time.time(). If this isn't what you are looking for maybe check out perf_counter()
import msvcrt
import time
def Countdown():
p = 3.00
alarm = time.time() + p
text = []
while True:
n = time.time()
if msvcrt.kbhit():
text.append(msvcrt.getche())
if n < alarm:
print(round(alarm - n))
else:
print("Time's up!")
break
Countdown()
Making a countdown timer with Python and Tkinter?