0

I have a GUI made by PyQT5. It contains a " plainTextEdit " widget and a push button as illustrated below:

enter image description here

After the push button is clicked, the worker thread will start. And if any " exception " or error occurs in the worker thread, it should be caught in the function in the main thread which starts the worker thread and the error message should be redirected to the " plainTextEdit " widget as below:

enter image description here

But my code does not operate in the way I expect. The GUI will crash if an exception occurs.

I am curious to know why the exception which occurs in the worker thread can not be caught in the the function in the main thread. Is it because the threads must communicate with each other by signals? Or is it because of any other mistakes in my code?

Below is the code of my main program:

from PyQt5 import QtCore, QtGui, QtWidgets
from main_window import Ui_Form
import sys

class Stream(QtCore.QObject):

    newText = QtCore.pyqtSignal(str)

    def write(self, data: str):
        self.newText.emit(data)

class Worker(QtCore.QRunnable):

    def __init__(self):
        super().__init__()

    def run(self, displayer: QtWidgets.QWidget):
        raise Exception()

class MyMainWindow(QtWidgets.QWidget, Ui_Form):

    def __init__(self, parent = None):
        super(MyMainWindow, self).__init__(parent)
        self.setupUi(self)

        self.threadPool = QtCore.QThreadPool()
        sys.stdout = Stream(newText = self.update_text)

        self.destroyed.connect(sys.exit)
        self.pushButtonStart.clicked.connect(self.start_working)

    def start_working(self):
        try:
            sys.stdout.write('Test start.\r')
            displayer = self.plainTextEdit
            worker = Worker()
            self.threadPool.start(lambda: worker.run(displayer))
        except Exception as e:
            sys.stdout.write(str(e))

    def update_text(self, data: str):
        cursor = self.plainTextEdit.textCursor()
        cursor.movePosition(QtGui.QTextCursor.End)
        cursor.insertText(data)
        self.plainTextEdit.setTextCursor(cursor)
        self.plainTextEdit.ensureCursorVisible()

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    window = MyMainWindow()
    window.show()
    sys.exit(app.exec_())

Below is the code for my GUI in the module called " main_window ":

from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_Form(object):
    def setupUi(self, Form):
        Form.setObjectName("Form")
        Form.resize(600, 300)
        self.gridLayout = QtWidgets.QGridLayout(Form)
        self.gridLayout.setObjectName("gridLayout")

        self.plainTextEdit = QtWidgets.QPlainTextEdit(Form)
        self.plainTextEdit.setObjectName("plainTextEdit")
        self.gridLayout.addWidget(self.plainTextEdit, 0, 0, 1, 1)
        spacerItem = QtWidgets.QSpacerItem(500, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)

        self.pushButtonStart = QtWidgets.QPushButton(Form)
        self.pushButtonStart.setObjectName("pushButtonStart")
        self.gridLayout.addWidget(self.pushButtonStart, 1, 0, 1, 1)

        self.retranslateUi(Form)
        QtCore.QMetaObject.connectSlotsByName(Form)

    def retranslateUi(self, Form):
        _translate = QtCore.QCoreApplication.translate
        Form.setWindowTitle(_translate("Form", "Form"))
        self.pushButtonStart.setText(_translate("Form", "Start"))

  • Trap the exception in the worker thread and emit an error signal. – ekhumoro Apr 21 '22 at 16:41
  • @ekhumoro: Thank you very much. I think your suggestion is the right way to fulfill what I want. I also found the explanation for the failure of my code here in another question of this website: [Catch a thread's exception in the caller thread?](https://stackoverflow.com/questions/2829329/catch-a-threads-exception-in-the-caller-thread). – thomas_chang Apr 22 '22 at 01:58

0 Answers0