PyQt5 GUI Being blocked despite QThread

Viewed 40

In my GUI I have a button which starts a subprocess to execute an Abaqus job. I have a QObject worker subclass to read the resulting .sta and .inp files and emit to pyqtSignal's some results to methods for updating the statusbar and progressbar.

I set the QThread / worker up based on this stackoverflow answer: https://stackoverflow.com/a/54458277/17337814, and at one point it was working perfectly but after some changes it's broken.

My progressbar will update correctly but if I touch anything on the GUI it freezes until the thread is closed. The statusbar message doesn't update at all, but the progress bar does change color when completed. I also have yet to test if the progress bar will update correctly if running multiple times...

Some code (sorry cannot provide entire code):

#subclass_module.py
class AbaqusProgress(QObject):
    finished = pyqtSignal()
    progress = pyqtSignal(int)
    message = pyqtSignal(str)
    completed = pyqtSignal(bool)

    def run(self, inp_path, wait_time=5):
        step_dict = self.return_steps(inp_path)
        i = 0
        status = None
        while status is None:
            print(i)
            if wait_time * i / 60 > 10:
                status = 'TIMEOUT'
                msg = 'Warning: Progress bar timed out after 15 minutes'
            QThread.sleep(wait_time)
            i += 1
            percent, step_name = self.return_percent(inp_path, step_dict)
            if percent < 0:
                percent = abs(percent)
                msg = 'Error: Simulation failed to converge'
                status = False
            elif percent == 100:
                msg = 'Simulation completed successfully'
                status = True
            else:
                msg = 'Simulation running, current step: ' + step_name
            self.progress.emit(percent)
            self.progress.emit(msg)
        self.completed.emit(status)
        self.finished.emit()

    def return_percent(self, ...):
        ...
    def return_steps(self, ...):
        ...
class MyMainWindow(QMainWindow):
    ... 


#myGUI_module.py

class myGUI(MyMainWindow):
    
    def __init__(self):
        super().__init__(<args for MyMainWindow>)
        self._thread = QThread(self)
        self._worker = myqt.AbaqusProgress()
        self._worker.moveToThread(self._thread)
        self._worker.progress.connect(self.progress_bar.setValue)
        self._worker.message.connect(self.status_bar.showMessage)
        self._worker.completed.connect(self.pb_chunk)
        self._thread.finished.connect(self._worker.deleteLater)
        ...

    ...

    def button_function(self):
        self.update_data()
        temp = os.getcwd()
        inp = self.data['path'] + '\\file.inp'
        sta = inp_path.replace('.inp', '.sta')
        if os.path.exists(sta):
            os.remove(sta)
        try:
            os.chdir(self.data['path'])
            tools.run_abaqus(inp,
                             abaqus_path=self.data['abaqus_path'])
            self._thread.start()
            QTimer.singleShot(1, lambda: self._worker.run(inp))
            os.chdir(temp)
        except FileNotFoundError:
            self.output_msg('Error: Project directory is incorrect '
                            + 'or does not exist')

    def pb_chunk(self, completed):
        color = 'green' if completed else 'red'
        self.progress_bar.setStyleSheet(
            'QProgressBar::chunk{background-color:' + color + '}')


    def closeEvent(self, event):
        if self._thread.isRunning():
            self._thread.quit()
        del self._thread
        del self._worker
        super(myGUI, self).closeEvent(event)

    ...

Can you identify why these problems are occurring?

Thank you!!

I've tried:

Using self._thread.finished.connect(lambda: worker.run(args)) in the myGUI init instead of the QTimer.singleshot() (no change but complicates arg transfer)

Some other things but I've forgotten them...

0 Answers
Related