Home > OS >  PySide6 QThread still freezing main GUI
PySide6 QThread still freezing main GUI

Time:07-06

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

CodePudding user response:

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.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):
        self.worker.some_file = 'some_file.txt'
        self.worker.moveToThread(self.thread)
        self.thread.started.connect(self.worker.run)
        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

  • Related