问题
I have written a Tkinter and I hope to have a Listener to monitor the Keyboard Input by Users. But when I use mainloop()
to start the Tkinter, the Listener cannot work together with it, and will start until I quit Tkinter.
I have tried to add this Listener in Tkinter sub-unit, but it does not work as the same.
def initialization():
print("Starting...")
print("Start listener...")
with mouse.Listener(on_click=onMouseClick) as listener:
listener.join()
if __name__ == "__main__" :
root = tk.Tk()
root.geometry('800x80')
root.resizable(height=True, width=True)
root.overrideredirect(False)
root.title('vENC Console')
OneBtn = Button(root, command=initialization, text="One Button", width='30')
root.mainloop()
How can I let them work together? Do I need to use multi-thread?
回答1:
Like practically all GUI toolkits, Tkinter is event driven. That means that Tkinter should handle mouse and keyboard events. Widgets can register that they're interested in event by adding bindings for certain events. Tkinter depends on the flow of events to work.
Essentially, the mainloop
waits for events to occur (keyboard, mouse, time-outs) and then calls any registered callbacks.
Adding another event handler separate from Tkinter will clash. On top of that, Tkinter is not thread-safe. If you must use threads you should make sure that only the main thread uses Tkinter functions and methods.
Basically, Tkinter and a Listener cannot work together.
So I would propose to you to use bind_all
instead.
By using the bind_all
method (read about it here) you can register a binding on the application level instead of for specific widgets.
回答2:
You can write it this way
listener = mouse.Listener(on_click=onMouseClick)
listener.start() # start thread
root.mainloop()
listener.stop() # stop thread
listener.join() # wait till thread really ends its job
And don't use return False
in onMouseClick
because it ends listener.
tkinter
has own methods to get keys and mouse events so maybe you should use them. Listener
can be useful if you have to catch event when tkinter's window is minimized and it doesn't get events from system.
EDIT:
import tkinter as tk
from pynput import mouse
def onMouseClick(*args):
print(args)
root = tk.Tk()
listener = mouse.Listener(on_click=onMouseClick)
listener.start() # start thread
root.mainloop()
listener.stop() # stop thread
listener.join() # wait till thread really ends its job
EDIT:
import tkinter as tk
from pynput import mouse
def onMouseClick(*args):
print(args)
def initialization():
global listener
print("Starting...")
print("Start listener...")
listener = mouse.Listener(on_click=onMouseClick)
listener.start() # start thread
if __name__ == "__main__" :
listener = None
root = tk.Tk()
btn = tk.Button(root, command=initialization, text="One Button")
btn.pack()
root.mainloop()
# stop listener if it was created
if listener: # if listener is not None:
print("Stop listener...")
listener.stop() # stop thread
listener.join() # wait till thread really ends its job
EDIT: example with button which stop listener
import tkinter as tk
from pynput import mouse
def onMouseClick(*args):
print(args)
def on_start():
global listener
if not listener:
print("Start listener...")
listener = mouse.Listener(on_click=onMouseClick)
listener.start() # start thread
else:
print("listener already running")
def on_stop():
global listener
if listener:
print("Stop listener...")
listener.stop() # stop thread
listener.join() # wait till thread really ends its job
listener = None # to inform that listener doesn't exist
else:
print("listener not running")
if __name__ == "__main__" :
print("Starting...")
listener = None # to keep listener
root = tk.Tk()
btn = tk.Button(root, command=on_start, text="Star Mouse Listener")
btn.pack()
btn = tk.Button(root, command=on_stop, text="Stop Mouse Listener")
btn.pack()
root.mainloop()
# stop listener if it was created
if listener: # if listener is not None:
print("Stop listener...")
listener.stop() # stop thread
listener.join() # wait till thread really ends its job
来源:https://stackoverflow.com/questions/57304574/how-can-a-tkinter-work-with-a-listener-together