2

I am currently trying to implement some threading functionality in my PySide6 GUI application. I followed a tutorial to try to get started (link is here), and I cannot seem to get it to work. Although that tutorial uses PyQt not PySide, the classes and structure is still similar, and it does seem to launch on another thread. Still though, it freezes the main GUI, which is not desired when this actually faces users.

Here is a sample of my code:

class Worker(QObject):
    finished = Signal(str)
    progress = Signal(int)

    def run(self, file):
        """Long-running task." that calls a separate class for computation""
        b = SeparateClass()
        b.doComputation()
        
        self.finished.emit()
class DataPlotting(QMainWindow):
    def __init__(self):
        self.thread = QThread()
        self.worker = Worker()
        self.report_builder = QPushButton('Call class that threads')
        self.report_builder.setEnabled(False)
        self.report_builder.clicked.connect(self.qthread_test)
    
    def qthread_test(self):
        file = 'some_file.txt'

        self.worker.moveToThread(self.thread)
        self.thread.started.connect(self.worker.run(file))
        self.worker.finished.connect(self.thread.quit)
        self.worker.finished.connect(self.worker.deleteLater)
        self.thread.finished.connect(self.thread.deleteLater)
        self.thread.start()
        return

This does accomplish the work that is in the Worker class and spit out the desired results, but it freezes the GUI. I am not really sure what I am doing wrong, as this approach is what has been suggested to prevent freezing GUIs for heavy computation.

Is there something that I am straight up missing? Or am I going about this the wrong way? Any help or guidance is appreciated

ccortez
  • 23
  • 3
  • 1
    `self.thread.started.connect(self.worker.run(file))` When your code executes that line it runs the function `self.worker.run(file)` immediately and assigns the result of that function, which is `None`, as the connected slot to the `thread.started` signal. – Alexander Jun 23 '22 at 23:56

1 Answers1

0

I am assuming that you make the appropriate calls to the super class during __init__ for your subclasses of QMainWindow and the QObject.

When your code executes self.thread.started.connect(self.worker.run(file)) that line it runs the function self.worker.run(file) immediately and assigns the result of that function, which is None, as the connected slot to the thread.started signal. Instead of passing the file path as a parameter you can assign it to the worker instance and have the run method grab the path from self during execution.

For example you can try something like this:

class Worker(QObject):
    finished = Signal(str)
    progress = Signal(int)

    def run(self):
        """Long-running task." that calls a separate class for computation"""
        file = self.some_file
        b = SeparateClass()
        b.doComputation()
        
        self.finished.emit()
class DataPlotting(QMainWindow):
    def __init__(self):
        self.report_builder = QPushButton('Call class that threads')
        self.report_builder.setEnabled(False)
        self.report_builder.clicked.connect(self.qthread_test)
        self.threads = []
    
    def qthread_test(self):
        worker = Worker()
        thread = QThread()
        worker.some_file = 'some_file.txt'
        worker.moveToThread(thread)
        thread.started.connect(worker.run)
        worker.finished.connect(thread.quit)
        worker.finished.connect(worker.deleteLater)
        thread.finished.connect(thread.deleteLater)
        thread.start()
        self.threads.append(thread)
        return

Alexander
  • 16,091
  • 5
  • 13
  • 29
  • Thank you! This was helpful, but it did lead to another issue. The finished signal from my Worker class seems to not work correctly. I was wondering if you may know why. The line `self.worker.finished.connect(self.thread.quit)` seems to run immediately instead of when the run class is actually finished. I feel like something is getting lost when emiting from the worker class, but I am not sure. – ccortez Jul 05 '22 at 19:51
  • @ccortez is it throwing an exception? – Alexander Jul 05 '22 at 20:31
  • @ccortez its possible that the thread is being destroyed because it is being overwritten. Please try making the adjustments i edited in my answer and see if that solves the problem. – Alexander Jul 05 '22 at 22:42
  • I ended up figuring it out with some help from your original answer, thank you! – ccortez Jul 06 '22 at 21:49