Взаимодействие с QTextBrowser из другого потока

При попытке вставить текст в textBrowser из другого потока - крашится программа. Причём, если использовать вместо QTextBrowser QLineEdit - то всё работает отлично.

import sys, os
from PyQt5 import QtWidgets, QtCore
from PyQt5.QtCore import Qt
from threading import Thread
from PyQt5.QtWidgets import QApplication, QWidget

class MyWin(QWidget):
    def __init__(self):
        super(QWidget, self).__init__()
        self.textBrowser = QtWidgets.QTextBrowser(self)

        Thread(target=self.set_text_foo).start()

    def set_text_foo(self):
        self.textBrowser.setText('success')


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

Ответы (1 шт):

Автор решения: Alexander Chernin

Для взаимодействия с графическими элементами интерфейса из других потоков, лучше использовать сигналы/слоты, а для этого воспользоваться Qt-шными потоками (QThread):

from PyQt5.QtCore import Qt, QThread, pyqtSignal

class TextFooThread(QThread):
    signal_textFoo = pyqtSignal(str)

    def run(self):
        self.signal_textFoo.emit('success')

class MyWin(QWidget):    

    def __init__(self):
        super(QWidget, self).__init__()
        self.textBrowser = QtWidgets.QTextBrowser(self)

        self.thread = TextFooThread(self)
        # Соединяем сигнал потока с методом окна, а
        # сами данные передаем через объект в очереди сообщений (Qt.QueuedConnection),
        # "развязывая", таким образом, обращение к объекту в главном потоке,
        # на случай синхронного доступа к последнему (то есть к textBrowser), 
        # что может привести к краху приложения
        self.thread.signal_textFoo.connect(self._text_from_thread, Qt.QueuedConnection)
        self.thread.start()

    def _text_from_thread(self, text):
        self.textBrowser.setText(text)
→ Ссылка