添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

The program below simply tests whether I can call root.destroy() of tkinter in a child thread. Though no error raised, I see a lot of posts in stackoverflow reminding people not to use tkinter in a child thread, so I wonder if calling root.destroy() in a child thread is not a good idea too, though I used tkinter in the main thread?

import tkinter
from tkinter import ttk
import time
import _thread
def callBackFunc():
    global LOOP_ACTIVE
    LOOP_ACTIVE = False
root = tkinter.Tk()
root.geometry('200x100')
chkValue = tkinter.BooleanVar()
chkValue.set(False)
chk = ttk.Checkbutton(root, variable=chkValue, text='Click me', command=callBackFunc)
chk.grid(column=0, row=0)
def loop_function():
    global LOOP_ACTIVE
    LOOP_ACTIVE = True
    while LOOP_ACTIVE:
        print(chk.state())
        time.sleep(5)
    print("you clicked me")
    root.destroy()
_thread.start_new_thread(loop_function, ())
root.mainloop()
print("printed after mainloop ends")
                None of the UI frameworks support doing UI operations on a secondary thread.  Windows is fairly forgiving about it, Linux tends to work until it crashes, Mac hates it.  The general rule is, don't do it.
– Tim Roberts
                Mar 10, 2021 at 4:08
                You can try using root.event_generate("<Destroy>") instead of calling root.destroy() directly.
– acw1668
                Mar 10, 2021 at 8:55

You can avoid calling destroy() in the child thread by periodically checking the flag in the main GUI thread by using the universal after() widget method to schedule them to occur.

In the code below I've added a check_loop_status() function that does that, and it will call root.destroy() if it discovers that the LOOP_ACTIVE flag is no longer set. To keep on process going, it schedules another call to itself before returning (which of course will never happen if destroy() got called).

Since this all that happens in the main thread, any call to destroy() will be fine.

import tkinter
from tkinter import ttk
import time
import _thread
DELAY = 1000 # milliseconds
root = tkinter.Tk()
root.geometry('200x100')
chkValue = tkinter.BooleanVar(value=False)
def callBackFunc():
    global LOOP_ACTIVE
    print("button was clicked")
    LOOP_ACTIVE = False
def check_loop_status():
    global LOOP_ACTIVE
    if not LOOP_ACTIVE:
        root.destroy()  # OK in this function.
    root.after(DELAY, check_loop_status)  # Check again after delay.
chk = ttk.Checkbutton(root, variable=chkValue, text='Click me', command=callBackFunc)
chk.grid(column=0, row=0)
def loop_function():
    global LOOP_ACTIVE
    while LOOP_ACTIVE:
        print(f'Checkbutton state: {chk.state()}')
        time.sleep(5)
LOOP_ACTIVE = True
_thread.start_new_thread(loop_function, ())
check_loop_status()  # Start periodic checking.
root.mainloop()
print("printed after mainloop ends")
        

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.