How can a Tkinter work with a Listener together?

给你一囗甜甜゛ 提交于 2021-01-06 18:22:43

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!