I have a GUI made by PyQT5. It contains a " plainTextEdit " widget and a push button as illustrated below:
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:
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"))