3

I am writing this software for a project homework, but I am having trouble with mixing threads and tkinter. The following piece works mostly as expected, but when I close it (after starting it in the Python shell), windows shows an error: "Python stopped working".

import threading
import time
import tkinter
import tkinter.ttk

class BTClient:
    def __init__(self, master):
        self.root = master
        self.root.bind("<Destroy>", self.on_destroy)

        self.t = threading.Thread(target=self.update)
        self.running = False

    def on_destroy(self, event):
        self.running = False

    def run_thread(self):
        self.running = True
        self.t.start()

    def update(self):
        while self.running:
            print("Update.")
            time.sleep(1)

def main(args):
    root = tkinter.Tk()
    client = BTClient(root)
    client.run_thread()
    root.mainloop()

if __name__ == "__main__":
    import sys
    main(sys.argv)

How can I solve that problem? Is it caused by the design I am using? Should I change it?

Edit 1: When I remove the self.root declaration in __init__ and only use the master reference the problem is solved, but I need to have references to the GUI objects, first to build the GUI and also to get input from them, so I don't know how to solve that. Maybe passing objects as arguments to everything that may need them?

7
  • have you tried to to encapsulate the thread in try/except to see what the error message is? I don't have tkinter experience, but similar problems arise in wxpython because the thread tries to access the window after its closed. Commented Oct 31, 2015 at 0:55
  • maybe try setting the thread to daemon self.t.setDaemon(True) Commented Oct 31, 2015 at 0:56
  • If I set it as daemon, the thread dies immediately after the main thread, right?, without any cleanup, which I think I need to do. Commented Oct 31, 2015 at 1:05
  • Yeah. Try moving the threaded method outside of the BTClient class, and add a try/except clause Commented Oct 31, 2015 at 1:08
  • 1
    I'm assuming that when the window closes, it deletes the BTClient instance and your thread still needs that instance (self.running) so its throwing an error Commented Oct 31, 2015 at 1:12

2 Answers 2

1

Its hard to know exactly whats happening without seeing your actual code, but I would make your threaded method a function outside of the BTClient and also move the thread outside of the client and add a call to thread.join() after the mainloop to have your thread finish its cleanup before the BTClient is deleted by the GC

def update():
    import time
    while thread._keep_alive:
        time.sleep(1)
        print("thread running")

thread = threading.Thread(target=update)
thread._keep_alive = True
thread.start()

at the end

thread._keep_alive = False
thread.join()
Sign up to request clarification or add additional context in comments.

1 Comment

The error does happen with this piece of code, I see no need of more code being posted, right?
0

So I added the line client.t.join() after root.mainloop() and that solves the problem even though I don't really know why. I think it's because python was destroying the tkinter objects when there were still references to them in other threads, so waiting for them to close solves it. Thanks.

1 Comment

yeah that's why. The join method prevents the client from being deleted from existence until the thread completes.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.