[英]Toggle key to run a thread then stop the thread when pressed again?
I'm currently working on a program and setup a toggle key that starts a thread when it's first clicked, and I want it to stop the thread when the key is pressed again.我目前正在开发一个程序并设置一个切换键,该键在第一次单击时启动线程,并且我希望它在再次按下该键时停止线程。 Currently I've tried this piece of code, but it came out with an error.目前我已经尝试了这段代码,但它出现了错误。
def on_press(key):
try: k = key.char
except: k = key.name
if key == (KeyCode(char='e')):
print("Key Pressed")
clicker = threading.Thread(target=run)
if running == False:
print("Starting")
clicker.start()
else:
print("Stopping")
clicker.join()
lis = keyboard.Listener(on_press=on_press)
lis.start() # start to listen on a separate thread
lis.join() # no this if main thread is polling self.keys
The error I get is:我得到的错误是:
raise RuntimeError("cannot join thread before it is started")
RuntimeError: cannot join thread before it is started**
You should check what you have in variable running
- ie.您应该检查变量running
中的内容 - 即。 print(running) - because it decides when to execute code in
if/else and it runs
click.join() directly after creating
Thread before you run
clicker.start()` print(running) - because it decides when to execute code in
and it runs
directly after creating
Thread before you run
clicker.start()`
As for me you should create therad inside if running == False
至于我, if running == False
,你应该在里面创建 therad
You should also use global
to assing values to external variable - now you create local clicker
which will be removed when it exits on_press
and you will not have access to this thread.您还应该使用global
将值分配给外部变量 - 现在您创建本地点击器,当它退出clicker
时将被on_press
,您将无法访问该线程。 You should also change value running
when you started thead`您还应该在启动 thead 时更改running
值`
BTW:顺便提一句:
For True/False
you should rather use is
instead of ==
对于True/False
,您应该使用is
而不是==
You can also use more readable if not running
instead of if running is False:
if not running
而不是if running is False:
I didn't test it我没有测试它
# from ... import ...
# --- functions ---
def on_press(key):
global running # inform function that it has to assign value to external variable
global clicker
try: # PEP8: don't put it in one line - it make code unreadable for human
k = key.char
except:
k = key.name
if key == KeyCode(char='e'):
print("Key Pressed")
if not running: # the same as `if running == False:`
print("Starting")
clicker = threading.Thread(target=run)
clicker.start()
running = True
else:
print("Stopping")
clicker.join()
running = False
# --- main ---
running = False # default value at start
lis = keyboard.Listener(on_press=on_press)
lis.start()
lis.join()
if you don't use running
in other places in code then you could use clicker = None
to control if thread is running.如果您不在代码中的其他地方使用running
,那么您可以使用clicker = None
来控制线程是否正在运行。
# from ... import ...
# --- functions ---
def on_press(key):
global clicker # inform function that it has to assign value to external variable
try: # PEP8: don't put it in one line - it make code unreadable for human
k = key.char
except:
k = key.name
if key == KeyCode(char='e'):
print("Key Pressed")
if not clicker:
print("Starting")
clicker = threading.Thread(target=run)
clicker.start()
else:
print("Stopping")
clicker.join()
clicker = None
# --- main ---
clicker = None # default value at start
lis = keyboard.Listener(on_press=on_press)
lis.start()
lis.join()
BTW:顺便提一句:
If thread is running then join()
waits for its end - but it doesn't kill it so you may wait forever.如果线程正在运行,则join()
等待它的结束 - 但它不会杀死它,所以你可能会永远等待。
You should use value running
also inside run()
to stop it.您应该在run()
中使用running
值来停止它。
def run():
while running:
#... code ...
or或者
def run():
while True:
#... code ...
if not running:
return
#... code ...
and then you have to set running
before start()
and join()
然后你必须在start()
和join()
之前设置running
if not running:
print("Starting")
clicker = threading.Thread(target=run)
running = True # it has to be before `start()`
clicker.start()
else:
print("Stopping")
running = False # it has to be before `join()`
clicker.join()
EDIT:编辑:
Minimal working code - I tested it.最少的工作代码 - 我测试了它。
from pynput import keyboard
import datetime
import time
import threading
# --- functions ---
def run():
print('Running thread')
while running:
print(datetime.datetime.now())
time.sleep(1)
print('Exiting thread')
def on_press(key):
global running # inform function that it has to assign value to external variable
global clicker
try: # PEP8: don't put it in one line - it make code unreadable for human
k = key.char
except:
k = key.name
if key == keyboard.KeyCode(char='e'):
print("Key Pressed")
if not running: # the same as `if running == False:`
print("Starting thread")
clicker = threading.Thread(target=run)
running = True # it has to be before `start()`
clicker.start()
else:
print("Stopping thread")
running = False # it has to be before `join()`
clicker.join()
# press `q` to exit
if key == keyboard.KeyCode(char='q'):
return False
# --- main ---
running = False # default value at start
try:
print("Starting program")
print("- press E to start/stop thread")
print("- press Q to exit")
print("- press Ctrl+C to exit")
lis = keyboard.Listener(on_press=on_press)
lis.start()
print("Listening ...")
lis.join()
print("Exiting program")
except KeyboardInterrupt:
print("Stoped by Ctrl+C")
else:
print("Stoped by Q")
finally:
if running:
running = False
clicker.join()
If the key pressed is the same as the start_stop_key, stop clicking if the running flag is set to true in the thread otherwise start it.如果按下的键与 start_stop_key 相同,则在线程中将运行标志设置为 true 时停止单击,否则启动它。 If the key pressed is the exit key, call the exit method in the thread and stop the listener如果按下的键是退出键,则调用线程中的exit方法并停止监听
start_stop_key = KeyCode(char='s')
exit_key = KeyCode(char='e')
...............
def on_press(key):
if key == start_stop_key:
if click_thread.running:
click_thread.stop_clicking()
else:
click_thread.start_clicking()
elif key == exit_key:
click_thread.exit()
listener.stop()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.