0

Save New Duplicate & Edit Just Text Twitter
# importing libraries
from PyQt6.QtWidgets import * 
from PyQt6.QtGui import * 
from PyQt6.QtCore import * 
import sys
import time

class Worker(QObject):
    finished = pyqtSignal()
    _stop = False
    def run(self):
        i=0
        print('Started')
        for i in range(5):
            if self._stop:
                print('Breaking')
                break
            time.sleep(1)
            i+=1
        self.finished.emit()
        print('Done')
    
    def stop(self):
        self._stop = True
        

class Example(QWidget):
  
    def __init__(self):
        super().__init__()
        self.initUI()
  
    def initUI(self):
        try:
            self.worker.stop()
            self.thread.wait()
        except (RuntimeError,AttributeError):
            pass
        print('Here')
        self.createThread()
        self.thread.started.connect(self.worker.run)
        self.worker.quit = False
        self.thread.finished.connect(lambda:print('Stopped'))
        self.thread.start()

        self.btn = QPushButton(self)
        self.btn.move(40, 80)
        self.btn.setText('Stop')
        self.btn.clicked.connect(self.initUI)
        self.setWindowTitle("Python")
        self.show()

    def createThread(self):
        self.thread = QThread()
        self.worker = Worker()
        self.worker.moveToThread(self.thread)
        self.worker.finished.connect(self.thread.quit)
        self.worker.finished.connect(self.worker.deleteLater)
        self.thread.finished.connect(self.thread.deleteLater)
  
if __name__ == '__main__':    
    App = QApplication(sys.argv)
    window = Example()
    sys.exit(App.exec())

I wrote an MVCE version of a problem I have been having.

The initUI function creates a window with a button in it. It also creates a thread that waits for 5 loops with a 1 second sleep each loop. When I click the button, it calls initUI again. This time, if the thread is still running, it calls the worker.stop function to stop the thread in between. When I do this, although the worker.run function finishes execution, the worker.finished signal is not emitted. However, the signal is emitted when the loop finishes on its own without pressing the button (i.e. waiting 5 seconds). Any explanation?

  • When you say that "the worker.finished signal is not emitted." are you referring to the `print('Stopped')`? – musicamante Feb 16 '23 at 18:33
  • The problem is caused by your frankly *totally daft* implementation that calls `initUI` every time the button is pressed. I suggest you consult some basic threading examples, and then completely re-think your code structure. – ekhumoro Feb 16 '23 at 21:52
  • @PUjwal Your implementation has many issues, starting with the fact that you are recreating each object every time, which does not make any sense. Since it seems clear that you want to run the threaded function *uniquely*, there is absolutely no point in creating it over and over: just create the thread and worker, start it, and eventually stop it and restart it again when you need it. Also, the `wait()` call is blocking and acts on the thread of the caller, so you must eventually call periodically `QApplication.processEvents()` at small intervals until the thread has actually quit. – musicamante Feb 17 '23 at 00:52
  • Thanks. That helped. The wait function was the issue. Fixed it with `processEvents()` I wrote this code hastily. I do not create each widget recursively in the actual code – P Ujwal Feb 18 '23 at 16:20

0 Answers0