0

I have a program that I want to, on button click, create a qthread and run some set of code. At the end I want the main thread to destroy the worker thread.

The following code shows one of my attempts. From what I can tell it only creates the thread on the first button click and on the second click it destroys the previous thread and creates and runs the work() function. If you wait to long in between button clicks you get the appearance like the first button click, that it does not run the work() function. Can anyone see something that I am doing wrong. I have a more complex example form someone else that I am trying to break down into a smaller part.( Pyqt5 qthread + signal not working + gui freeze )

Code:

import time
import sys

from PyQt5.QtCore import QObject, QThread, pyqtSignal, pyqtSlot
from PyQt5.QtWidgets import QApplication, QPushButton, QTextEdit, QVBoxLayout, QWidget


class Worker(QObject):
    """
    Must derive from QObject in order to emit signals, connect slots to other signals, and operate in a QThread.
    """
    sigDone = pyqtSignal(int)

    def __init__(self, id: int):
        print("Here 11")
        super().__init__()
        print("Here 9")
        self.__id = id

    @pyqtSlot()
    def work(self):
      print("Here 10")
      for count in range(20):
          print("ID: " + str(self.__id) + ", Count: " + str(count))
          time.sleep(0.1)
          app.processEvents()  # this could cause change to self.__abort
      self.sigDone.emit(self.__id)
      #Need a done signal.          

class MyWidget(QWidget):
    def __init__(self):
        super().__init__()
        print("Here 1")
        self.setWindowTitle("Thread Example")
        form_layout = QVBoxLayout()
        self.setLayout(form_layout)
        self.resize(400, 400)
        print("Here 2")
        self.btnStartWorker = QPushButton()
        self.btnStartWorker.clicked.connect(self.start_worker)
        self.btnStartWorker.setText("Start Worker")
        form_layout.addWidget(self.btnStartWorker)

        self.__threads = None

    def start_worker(self):
        print("Here 3")
        worker = Worker(999)
        thread = QThread()
        print("Here 4")
        self.__threads = []
        self.__threads.append(thread)
        print("Here 5")
        worker.moveToThread(thread)
        worker.sigDone.connect(self.workerDone)
        print("Here 6")
        thread.started.connect(worker.work)
        print("Here 7")
        thread.start()
        print("Here 8")    

    @pyqtSlot(int)
    def workerDone(self, threadNumber):
        print("Here 12")
        print("Thread " + str(threadNumber) + " is done.")
        for thread in self.__threads:
            thread.quit()
            thread.wait()
        print("Here 13")

if __name__ == "__main__":
    app = QApplication([])

    form = MyWidget()
    form.show()

    sys.exit(app.exec_())

Results from some button clicks:

E:\myCode\python\pyQt>python3 pyQtv6.py
Here 1
Here 2
Here 3
Here 11
Here 9
Here 4
Here 5
Here 6
Here 7
Here 8
Here 3
Here 11
Here 9
Here 4
QThread: Destroyed while thread is still running
Here 5
Here 6
Here 7
Here 8
Here 10
ID: 999, Count: 0
ID: 999, Count: 1
ID: 999, Count: 2
ID: 999, Count: 3
ID: 999, Count: 4
ID: 999, Count: 5
ID: 999, Count: 6
ID: 999, Count: 7
ID: 999, Count: 8
ID: 999, Count: 9
ID: 999, Count: 10
ID: 999, Count: 11
ID: 999, Count: 12
ID: 999, Count: 13
ID: 999, Count: 14
ID: 999, Count: 15
ID: 999, Count: 16
ID: 999, Count: 17
ID: 999, Count: 18
ID: 999, Count: 19
Here 12
Thread 999 is done.
Here 13
Here 3
Here 11
Here 9
Here 4
Here 5
Here 6
Here 7
Here 8
Here 3
Here 11
Here 9
Here 4
QThread: Destroyed while thread is still running
Here 5
Here 6
Here 7
Here 8
NDEthos
  • 507
  • 6
  • 17
  • Could you explain what the problem is? test changing worker to self.worker, the local variables are destroyed when the function finishes executing, in the case of thread it is not destroyed since you store it in a list but worker is eliminated. – eyllanesc Mar 28 '18 at 03:56
  • It seems you put me on to something. The example I linked to saves the thread and worker object as a tuple. I was only saving the thread to keep it from being garbage collected. I still have some other errors when I change "self.__threads.append(thread)" to self.__threads.append((thread, worker)) but they are ones I can fix. Thanks. Oh, the problem was that on first click you only get 1,2,3,11,9,4,5,6,7,8 to print, in that order. Then on second click you get the counting to print, 0 to 19. If you wait to long between button clicks then you get the 1 through 8 sequence again. – NDEthos Mar 28 '18 at 04:11
  • Do you still have problems with the changes? If so, explain what your current problem is. – eyllanesc Mar 28 '18 at 04:23
  • 'tuple' object has no attribute 'quit' but as I said I have that handled. It is only an access issue b/c it went form being a list of threads to a list of tuples. – NDEthos Mar 28 '18 at 04:31
  • `for some_value in self.__threads: thread, worker = some_value thread.quit() thread.wait()` – eyllanesc Mar 28 '18 at 04:32

0 Answers0