PyQt5 изменение QTextBrowser в QThread

При попытке изменить текст в QTextBrowser из потока QThread программа просто вылетает, а текст ошибки Qt не пишет.

Нужно каждую секунду менять текст и чтобы окно не висло.

Если заменить TextBrowser на прогресс бар - то всё работает нормально. Так как это исправить?

from PyQt5.QtWidgets import *
from PyQt5.QtCore import QThread
import sys
import time


class Example(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.tb = QTextBrowser(self)
        self.tb.setGeometry(30, 30, 100, 100)
        self.btn = QPushButton('Start', self)
        self.btn.move(50, 150)
        self.setGeometry(300, 300, 200, 200)
        self.setWindowTitle("Python")
        self.dt = DrawThread(self)

        self.btn.clicked.connect(self.doAction)

    def doAction(self):
        self.dt.start()


class DrawThread(QThread):
    def __init__(self, mainwindow, parent=None):
        super().__init__()
        self.mw = mainwindow
        self.mw.tb.setText("123")  # Тут всё работает

    def run(self):
        for i in range(100):
            time.sleep(1)
            self.mw.tb.setText(str(i))  # Здесь вылетает


if __name__ == '__main__':
    App = QApplication(sys.argv)
    window = Example()
    window.show()

    sys.exit(App.exec())```

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

Автор решения: eri

Управлять ui в qt можно только из главного треда. Чтоб решить эту задачу создай слот с параметром текста в главном потоке. В дополнительном потоке создай сигнал. Доп поток эмитит сигнал, а слот приняв его делает setText.

Все взаимодействия между объектами в разных тредах просто так не выполняются. У меня питон выдавал ошибку перед падением)

→ Ссылка
Автор решения: S. Nick

Нельзя обращаться из дополнительного потока к виджетам основного окна! Надо использовать сигналы и слоты, но в вашем случае дополнительный поток вообще не нужен.

Вам достаточно использовать QTimer.

import sys
#import time
from PyQt5.QtCore import QTimer
from PyQt5.QtWidgets import QWidget, QApplication, \
    QTextBrowser, QPushButton, QVBoxLayout


class Example(QWidget):
    def __init__(self):
        super().__init__()
        self.i = 0

        self.tb = QTextBrowser()
        self.tb.setText('Hello World')
        
        self.btn = QPushButton('Start')
        self.btn.clicked.connect(self.doAction)

        layout = QVBoxLayout(self)
        layout.addWidget(self.tb)        
        layout.addWidget(self.btn)
        
        self.timer = QTimer()                                # +++
        self.timer.setInterval(1000)   # Миллисекунды        # +++
        self.timer.timeout.connect(self.updateTime)          # +++ 

    def doAction(self):
        if self.btn.text() == 'Start':
            self.timer.start()
            self.btn.setText('Stop')
        else:
            self.timer.stop()
            self.btn.setText('Start')
            
    def updateTime(self):                                    # +++ 
        self.tb.setText(f'{self.i}')
        self.i += 1
        

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = Example()
    window.setWindowTitle("Python")
    window.show()
    sys.exit(app.exec_())

введите сюда описание изображения

→ Ссылка