QThread: Destroyed while thread is still running
Asked Answered
K

3

26

I'm having problem with QThreads in python. I want to change background color of label. But My application crash while starting. "QThread: Destroyed while thread is still running"

   class MainWindow(QMainWindow):
      def __init__(self):
          QMainWindow.__init__(self)
          self.ui = Ui_MainWindow()
          self.ui.setupUi(self)

          statusTh = statusThread(self)
          self.connect(statusTh, SIGNAL('setStatus'), self.st, Qt.QueuedConnection)
          statusTh.start()

      def st(self):
          if self.status == 'ON':
              self.ui.label.setStyleSheet('background-color:green')
          else:
              self.ui.label.setStyleSheet('background-color:red')

  class statusThread(QThread):
      def __init__(self, mw):
          super(statusThread, self).__init__()

      def run(self):
          while True:
              time.sleep(1)
              self.emit(SIGNAL('setStatus'))

  if __name__ == "__main__":
      app = QApplication(sys.argv)
      main_window = MainWindow()
      main_window.show()
      sys.exit(app.exec_())
Keeleykeelhaul answered 29/3, 2013 at 11:59 Comment(5)
A Qt-style solution, assign main window as statusTh's parent, namely, super(statusThread, self).__init__(mw).Arbela
Just for information, this is basically the same thing: in this case, the parent will keep the reference to the thread instance and therefore it will not be garbage collected.Tsarina
Can anyone please explain , what does that Qt.QueuedConnection means in the above question ?Involutional
so basically it's just a typo?Entropy
The super().__init__() call that's in the example above is evidently a typo, as it does nothing with the mw.Slaver
T
46

You're not storing a reference to the thread after it's been created, which means that it will be garbage collected (ie. destroyed) some time after the program leaves MainWindows __init__. You need to store it at least as long as the thread is running, for example use self.statusTh:

self.statusTh = statusThread(self)
self.connect(self.statusTh, SIGNAL('setStatus'), self.st, Qt.QueuedConnection)
self.statusTh.start()
Tsarina answered 29/3, 2013 at 12:8 Comment(4)
Sorry, I am novice in Python. I can't understand. How can I need to store the reference?Keeleykeelhaul
Just as i wrote in my answer. By assigning the instance of statusThread(self) to a local variable (ie. without self. in front of it), it will be garbage collected when the local variable goes out of scope (which it does when __init__ of MainWindow is finished). If you store the reference in a member variable of the MainWindow class (ie. with self. in front of it), it will not go out of scope when __init__ is done, resulting in the thread object not being garbage collected.Tsarina
I would give 10 upvotes! Nice answer - saved me a lot of time and grief! I think you should move the comment text to the answer as well.Calbert
Excuse me, but if you dont want to store the references - is there any method to create a new reference to object(thread)? I have a lot of methods which are need to work concurrently.Heyes
S
0

I know it's quite necroposting but this may be useful. In the main section of your script, a first level customized widget need to be stored in variable, not only created. For example I have a custom widget class called MainWindow that create a QThread. My main is like that:

from myPackage import MainWindow
if __name__ == "__main__":
    app = QApplication([])    
    widget=MainWindow()    
    sys.exit(app.exec())

if I avoid the widged = definition and only call for MainWindow(), my script will crash with QThread: Destroyed while thread is still running

Summand answered 4/9, 2022 at 6:33 Comment(1)
The OP already does that. Besides, avoiding it is quite wrong in principle anyway, since the object would be garbage collected, similarly to what the currently accepted answer already explains. If you just do MainWindow() instead of widget = MainWindow(), that window will probably never show at all anyway. If it does, you are making wrong assumptions in your code that could be probably considered bad practice or at least improperly justified, at least in this context. Besides, your code never calls widget.show(), which would make the app just run on background, consuming resources.Nevers
H
-1

Add statusTh.wait() after statusTh.start():

...
statusTh.start()
statusTh.wait()
...
Hippodrome answered 23/3, 2023 at 13:58 Comment(1)
Just no. QThread.wait() is blocking for the calling thread, similarly to Python's join(). It will simply freeze the whole program on startup (since it's called in the main window's __init__), as it completely blocks the event loop.Nevers

© 2022 - 2024 — McMap. All rights reserved.