PyQt5. textBrowser.append не работает при вызове во второстепенном потоке
from PyQt5 import QtWidgets, QtCore
from mydesign import Ui_MainWindow
import sys
from time import sleep
from threading import Thread
import datetime
from PyQt5.QtCore import QRunnable, QThreadPool
class Runnable(QRunnable):
def __init__(self, this):
super().__init__()
self.this = this
def run(self):
while not self.this.isClosed:
sleep(1)
ctime = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
self.this.ui.textBrowser.append(ctime) # <-- Error!
class mywindow(QtWidgets.QMainWindow):
def __init__(self):
super(mywindow, self).__init__()
self.this = self
self.isClosed = False
self.setWindowOpacity(0.95)
self.bt_count = 0
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.ui.pushButton.clicked.connect(
self.button_evt
)
self.runTasks() # <-- Error!
def button_evt(self):
self.ui.textBrowser.setText(
"Вы нажали на кнопку %d раз(а)" % self.bt_count)
self.bt_count += 1
def keyPressEvent(self, e):
if e.key() == QtCore.Qt.Key_End:
self.close()
exit()
def thread(self):
self.t1 = Thread(target=self.Operation, daemon=True)
self.t1.start()
def runTasks(self):
pool = QThreadPool.globalInstance()
runnable = Runnable(self)
pool.start(runnable)
def event(self, event):
if event.type() == QtCore.QEvent.Close:
print(f"Oкно закрытo (QCloseEvent).")
self.isClosed = True
return QtWidgets.QWidget.event(self, event)
app = QtWidgets.QApplication([])
application = mywindow()
application.show()
sys.exit(app.exec())
Вывод:
Вываливаются непредсказуемые ошибки.
Так как все-таки вызвать textBrowser.append в другом потоке?
Ответы (2 шт):
Автор решения: S. Nick
→ Ссылка
НЕЛЬЗЯ взаимодействовать с виджетами в дополнительном потоке. Сигналы и слоты используются для связи между объектами. Механизм сигналов и слотов - центральная особенность Qt и, вероятно, часть, которая больше всего отличается от функций, предоставляемых другими фреймворками. Больше https://doc.qt.io/qt-5/signalsandslots.htmlНет необходимости использовать дополнительные библиотеки (
time,threading,datetime).
Вот вам одно из возможных решений:
import sys
#from time import sleep
#from threading import Thread
#import datetime
from PyQt5 import QtWidgets, QtCore, QtGui
from PyQt5.Qt import *
# ? from mydesign import Ui_MainWindow
class WorkThread(QThread):
threadSignal = pyqtSignal(str)
def __init__(self):
super().__init__()
def run(self, *args, **kwargs):
while True:
self.msleep(1000)
# ctime = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
ctime = QDateTime.currentDateTime().toString("yyyy-MM-dd hh:mm:ss")
self.threadSignal.emit(ctime)
class MyWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.bt_count = 0
self.setWindowOpacity(0.95)
self.centralWidget = QtWidgets.QWidget()
self.setCentralWidget(self.centralWidget)
self.textBrowser = QTextBrowser()
self.pushButton = QPushButton('Button')
self.pushButton.clicked.connect(self.button_evt)
self.layout = QtWidgets.QGridLayout(self.centralWidget)
self.layout.addWidget(self.textBrowser)
self.layout.addWidget(self.pushButton)
self.runTasks()
def button_evt(self):
self.bt_count += 1
self.textBrowser.setText(
"Вы нажали на кнопку %d раз(а)" % self.bt_count)
def keyPressEvent(self, e):
if e.key() == QtCore.Qt.Key_End:
self.close()
# exit()
def runTasks(self):
self.thread = WorkThread()
self.thread.threadSignal.connect(self.on_threadSignal)
self.thread.start()
def on_threadSignal(self, ctime):
self.textBrowser.append(ctime)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
application = MyWindow()
application.show()
sys.exit(app.exec_())

