Search code examples
multithreadingqtpyqt5qthread

Why threading does not work in PyQt5?


Here is part of the code:

    ...
    self.startButton.clicked.connect(self.conc_thread)


def conc(self):
    self.textField.clear()
    word=self.searchBox.text()
    path=r'D:\\python1\wxPython\NYConc\Fiction'
    for filename in glob.glob(os.path.join(path, '*.txt')):
        try:
            file=open(filename, 'r')
            read=file.read()
            file.close()
            pattern=re.findall(r'.{40} '+word+r' .{40}', read)
            for i in pattern:
                self.textField.append(i)
        except:
            continue

def conc_thread(self):
    tg=threading.Thread(target=self.conc)
    tg.start()

It gives me this error message: "QObject: Cannot create children for a parent that is in a different thread. (Parent is QTextDocument(0xd08b98), parent's thread is QThread(0xc6f620), current thread is QThread(0x4a2c810)"

How can I solve that, please?


Solution

  • Given that your self.textField is a QTextEdit, whenever you call its append method, a QTextCursor is created as a child of the QTextEdit underlying QTextDocument object. What's wrong with that? Qt will not allow any QObject-derived class to have children 'living' in a thread different from the parent's one.
    How to solve that? Since you're already using them, let's employ signals and slot.

    First define a signal like this:

    appendText = pyqtSignal(str)
    

    and the corresponding slot:

    def appendToTextField(self, text):
        self.textField.append(text)
    

    connect them:

    self.appendText.connect(self.appendToTextField)
    

    then instead of:

    for i in pattern:
        self.textField.append(i)
    

    do:

    for i in pattern:
        self.appendText.emit(i)
    

    The appendToTextField slot is supposed to run in the right thread, the one where the QTextEdit underlying QTextDocument live, thus Qt will let new children be added to it.