Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
118 views
in Technique[技术] by (71.8m points)

python 3.x - Use tkinter virtual event from thread

I would like to update a Tkinter Label from a Thread using a virtual event.

from tkinter import *
from tkinter import ttk
import threading
import time


def run_test_event():
    while True:
        root.event_generate("<<test_eventA>>")
        root.event_generate("<<test_eventB>>")
        time.sleep(1)


if __name__ == '__main__':
    root = Tk()
    l = ttk.Label(root, text="Starting...")
    l.grid()
    l.bind('<Enter>', lambda e: l.configure(text='Moved mouse inside'))
    l.bind('<<test_eventA>>', lambda e: l.configure(text='test_eventA'))
    l.bind('<<test_eventB>>', print('test_eventB'))

    threading.Thread(target=run_test_event).start()
    root.mainloop()

Console print this at startup:

test_eventB

Console print this when GUI is closed:

Exception in thread Thread-1:
PythonPython38libkinter\__init__.py", line 1849, in event_generate
    self.tk.call(args)
RuntimeError: main thread is not in main loop

Label is never updated and does not display test_eventA

Setting the Thread as daemon does help. It avoid to generate above Exception but still the label is not updated. Any idea ?

question from:https://stackoverflow.com/questions/66061142/use-tkinter-virtual-event-from-thread

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

You are generating the virtual event on root window, not the label. You should call .event_generate() on the label:

from tkinter import *
from tkinter import ttk
import threading
import time


def run_test_event(label):
    while True:
        label.event_generate("<<test_eventA>>")
        label.event_generate("<<test_eventB>>")
        time.sleep(1)


if __name__ == '__main__':
    root = Tk()
    l = ttk.Label(root, text="Starting...")
    l.grid()
    l.bind('<Enter>', lambda e: l.configure(text='Moved mouse inside'))
    l.bind('<<test_eventA>>', lambda e: l.configure(text='test_eventA'))
    l.bind('<<test_eventB>>', lambda e: print('test_eventB')) # should use lambda here

    # pass label to target function
    threading.Thread(target=run_test_event, args=(l,), daemon=True).start()
    root.mainloop()

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...