0

I created a GUI in PyQT5 which consisted of 2 QPlainTextEdit widgets. Each QPlainTextEdit widget should show standard output of one of 2 worker threads of my program respectively. The 2 worker threads were assigned different arguments to specify to which QPlainTextEdit widget their standard output should be redirected.

However, I found if I implemented this program by putting the "start" function of the instance of QThreadPool in a for-loop, both worker threads would be assigned arguments of the same value and their output would be redirected to the same QPlainTextEdit widget.

Below is the code of my main program:

from PyQt5 import QtCore, QtWidgets, QtGui
import sys, os

from mainWindow import Ui_Form

class MyMainWindow(QtWidgets.QDialog, Ui_Form):

    def __init__(self, parent = None):

        super(MyMainWindow, self).__init__(parent)
        self.setupUi(self)
        self.pushButton.clicked.connect(self.start_working)
        sys.stdout = Stream(newText = self.update_text)

    def start_working(self):

        self.pool = QtCore.QThreadPool()
        for taskID in {'taskA', 'taskB'}:
            worker = Worker()
            self.pool.start(lambda: worker.run(taskID))

    def update_text(self, output: tuple):

        displayer = self.plainTextEditA if output[0] == 'taskA' else self.plainTextEditB
        cursor = displayer.textCursor()
        cursor.movePosition(QtGui.QTextCursor.End)
        cursor.insertText(f'{output[0]} - {output[1]}\n')
        displayer.setTextCursor(cursor)
        displayer.ensureCursorVisible()

class Worker(QtCore.QRunnable):

    def run(self, taskID):
        for index in range(1000):
            sys.stdout.write((taskID, index))

class Stream(QtCore.QObject):

    newText = QtCore.pyqtSignal(tuple)

    def write(self, output: tuple):
        self.newText.emit(output)

if __name__ == '__main__':

    app = QtWidgets.QApplication(sys.argv)
    window = MyMainWindow()
    window.show()
    sys.exit(app.exec_())

Below is the code for GUI in the module named "mainWindow":

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_Form(object):
    def setupUi(self, Form):
        Form.setObjectName("Form")
        Form.resize(597, 298)
        self.gridLayout = QtWidgets.QGridLayout(Form)
        self.gridLayout.setObjectName("gridLayout")
        self.label = QtWidgets.QLabel(Form)
        self.label.setObjectName("label")
        self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
        self.label_2 = QtWidgets.QLabel(Form)
        self.label_2.setObjectName("label_2")
        self.gridLayout.addWidget(self.label_2, 0, 2, 1, 1)
        self.plainTextEditA = QtWidgets.QPlainTextEdit(Form)
        self.plainTextEditA.setObjectName("plainTextEditA")
        self.gridLayout.addWidget(self.plainTextEditA, 1, 0, 1, 2)
        self.plainTextEditB = QtWidgets.QPlainTextEdit(Form)
        self.plainTextEditB.setObjectName("plainTextEditB")
        self.gridLayout.addWidget(self.plainTextEditB, 1, 2, 1, 2)
        spacerItem = QtWidgets.QSpacerItem(376, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.gridLayout.addItem(spacerItem, 2, 1, 1, 2)
        self.pushButton = QtWidgets.QPushButton(Form)
        self.pushButton.setObjectName("pushButton")
        self.gridLayout.addWidget(self.pushButton, 2, 3, 1, 1)

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

    def retranslateUi(self, Form):
        _translate = QtCore.QCoreApplication.translate
        Form.setWindowTitle(_translate("Form", "Form"))
        self.label.setText(_translate("Form", "A"))
        self.label_2.setText(_translate("Form", "B"))
        self.pushButton.setText(_translate("Form", "PushButton"))

I also found if I changed the "start_working" function by moving the "start" function of the QThreadPool instance to an independent function like "run_thread" in the following code, the output of worker threads would be redirected to the correct QPlainTextEdit widgets.

def start_working(self):

    self.pool = QtCore.QThreadPool()
    for taskID in {'taskA', 'taskB'}:
        self.run_thread(taskID)

def run_thread(self, taskID: str):

    worker = Worker(self)
    self.pool.start(lambda: worker.run(taskID)

Can anyone tell me why this is so?

0 Answers0