《从子线程中回调更新tableview》报错 Cannot cr

2019-10-25  本文已影响0人  昵称违法

描述:在主UI线程中,启动了一个子线程进行计算,计算完毕,回调更新UI中的一个tabelview。界面已经更新,但是线程出现报错。

程序结构

QObject: Cannot create children for a parent that is in a different thread.
(Parent is QHeaderView(0x1ec5ce55eb0), parent's thread is QThread(0x1ec4d609c30), current thread is BigWorkThread(0x1ec5cdd4820)
QBasicTimer::start: Timers cannot be started from another thread
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QHeaderView(0x1ec5ce58d70), parent's thread is QThread(0x1ec4d609c30), current thread is BigWorkThread(0x1ec5cdd4820)
QBasicTimer::start: Timers cannot be started from another thread
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QTableView(0x1ec4d629d40), parent's thread is QThread(0x1ec4d609c30), current thread is BigWorkThread(0x1ec5cdd4820)

以下是回调函数:

    #线程计算完毕,回调,显示计算结果    
    def display_result_df_callBack(self, df):
        model = pandasModel(df)
        view = self.tableView_result
        view.setModel(model)          #调试后发现,这一句是报错的根源
        view.show()        
        logging.info("回调函数")

查询后发现:
It is not good to access the model directly from another thread since the QObjects are not thread-safe, instead it creates a QObject that sends the data to the main thread through signals, in this case for a simple operation I created the slot update_item that receives the row, column and data.

How to correctly update view in pyQt after editing abstract model in another thread?

import sys
import threading
import time

from PyQt5 import QtCore, QtGui, QtWidgets


class CopterDataModel(QtCore.QAbstractTableModel):
    def __init__(self, parent=None):
        super(CopterDataModel, self).__init__(parent)
        self.data_contents = [[1, 2]]

    def rowCount(self, n=None):
        return len(self.data_contents)

    def columnCount(self, n=None):
        return 2

    def data(self, index, role):
        row = index.row()
        col = index.column()
        # print('row {}, col {}, role {}'.format(row, col, role)) #for debug
        if role == QtCore.Qt.DisplayRole:
            return self.data_contents[row][col] or ""

    def setData(self, index, value, role=QtCore.Qt.EditRole):
        if not index.isValid():
            return False

        if role == QtCore.Qt.EditRole:
            self.data_contents[index.row()][index.column()] = value
            print("edit", value)
            self.dataChanged.emit(
                index, index, (QtCore.Qt.EditRole,)
            )  # NOT WORKING
        else:
            return False
        return True

    def flags(self, index):
        return QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled

    @QtCore.pyqtSlot(int, int, QtCore.QVariant)
    def update_item(self, row, col, value):
        ix = self.index(row, col)
        self.setData(ix, value)


class SignalManager(QtCore.QObject):
    fooSignal = QtCore.pyqtSignal(int, int, QtCore.QVariant)


if __name__ == "__main__":

    def timer(obj):
        idc = 1001
        while True:
            obj.fooSignal.emit(0, 0, idc)
            idc += 1
            time.sleep(1)

    app = QtWidgets.QApplication.instance()
    if app is None:
        app = QtWidgets.QApplication(sys.argv)

    foo = SignalManager()

    tableView = QtWidgets.QTableView()
    myModel = CopterDataModel()
    foo.fooSignal.connect(myModel.update_item)

    tableView.setModel(myModel)

    tableView.show()

    t = threading.Thread(target=timer, args=(foo,), daemon=True)
    t.start()

    app.exec_()

解决方法
线程中在定义一个信号(名字:displayResultAfterCalculating(list)----计算完毕显示计算结果,返回一个list,list中装一个dataframe)
线程计算完毕后:带上计算结果,发送一个该信号
主线程接收信号,并用该计算结果更新ui
结束!!!!

上一篇下一篇

猜你喜欢

热点阅读