Python 为什么在PySide2表模型中可以发出dataChanged(),但不能发出layoutChanged()?

Python 为什么在PySide2表模型中可以发出dataChanged(),但不能发出layoutChanged()?,python,pyside2,Python,Pyside2,我是新来的。目前,我正在尝试学习如何从不同的线程更新表模型,然后如何为其立即获得显示更新。我阅读了文档,发现了dataChanged()和layoutChanged()信号。虽然dataChanged()工作正常,但任何发出layoutChanged()的尝试都会失败,原因是: 'QObject::connect: Cannot queue arguments of type 'QList<QPersistentModelIndex>' (Make sure 'QLi

我是新来的。目前,我正在尝试学习如何从不同的线程更新表模型,然后如何为其立即获得显示更新。我阅读了文档,发现了
dataChanged()
layoutChanged()
信号。虽然
dataChanged()
工作正常,但任何发出
layoutChanged()
的尝试都会失败,原因是:

'QObject::connect: Cannot queue arguments of type 'QList<QPersistentModelIndex>' (Make sure 'QList<QPersistentModelIndex>' is registered using qRegisterMetaType().)
搜索这个特定的错误并没有给我任何可以转化为工作代码的东西。我没有显式地使用任何
QList
QPersistentModelIndex
,但由于我选择的构造,当然可以隐式地使用它们

我做错了什么

class TimedModel(QtCore.QAbstractTableModel):

    def __init__(self, table, view):
        super(TimedModel, self).__init__()
        self.table = table
        self.view =  view
        self.setHeaderData(0, Qt.Horizontal, Qt.AlignLeft, Qt.TextAlignmentRole)
        self.rows = 6
        self.columns = 4
        self.step = 5
        self.timer = Thread(
            name = "Timer",
            target = self.tableTimer,
            daemon = True)
        self.timer.start()
        self.random = Random()
        self.updated = set()

    @staticmethod
    def encode(row, column):
        return row << 32 | column

    def data(self, index, role):

        if role == Qt.DisplayRole or role == Qt.EditRole:
            return f'Data-{index.row()}-{index.column()}'

        if role == Qt.ForegroundRole:
            encoded = TimedModel.encode(index.row(), index.column())
            return QBrush(Qt.red if encoded in self.updated else Qt.black)            

        return None

    def rowCount(self, index):
        return self.rows

    def columnCount(self, index):
        return self.columns

    def headerData(self, col, orientation, role):
        if orientation == Qt.Vertical:
            # Vertical
            return super().headerData(col, orientation, role)
        # Horizontal
        if not 0 <= col < self.columns:
            return None
        if role == Qt.DisplayRole:
            return f'Data-{col}'
        if role == Qt.TextAlignmentRole:
            return int(Qt.AlignLeft | Qt.AlignVCenter)
        return super().headerData(col, orientation, role)

    def tableTimer(self):
        while True:
            time.sleep(5.0)
            randomRow = self.random.randint(0, self.rows)
            randomColumn = self.random.randint(0, self.columns)
            encodedRandom = TimedModel.encode(randomRow, randomColumn)
            if encodedRandom in self.updated:
                self.updated.remove(encodedRandom)
            else:
                self.updated.add(encodedRandom)
            updatedIndex = self.createIndex(randomRow, randomColumn)
            self.dataChanged.emit(updatedIndex, updatedIndex)

            '''this here does not work:'''
            self.layoutAboutToBeChanged.emit()
            self.rows += self.step
            self.layoutChanged.emit()

class MainWindow(QtWidgets.QMainWindow):

    def __init__(self):
        QtWidgets.QMainWindow.__init__(self)

        self.timedTable = QTableView()
        self.model = TimedModel(self.timedTable, self)

        self.timedTable.setModel(self.model)
        headerView = self.timedTable.horizontalHeader()
        headerView.setStretchLastSection(True)
        self.setCentralWidget(self.timedTable)

        self.setGeometry(300, 300, 1000, 600)
        self.setWindowTitle('Timed Table')
        self.show()

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    app.name = "Timed Table Application"
    window = MainWindow()
    window.show()
    app.exec_()
类时间模型(QtCore.QAbstractTableModel):
定义初始化(自、表、视图):
super(TimedModel,self)。\uu初始化
self.table=表格
self.view=view
self.setHeaderData(0,Qt.Horizontal,Qt.AlignLeft,Qt.TextAlignmentRole)
self.rows=6
self.columns=4
self.step=5
self.timer=线程(
name=“Timer”,
目标=self.tableTimer,
daemon=True)
self.timer.start()
self.random=random()
self.updated=set()
@静力学方法
def编码(行、列):
返回行以下代码:

self.layoutaboutbechanged.emit()
self.rows+=self.step
self.layoutChanged.emit()
创建与
QPersistentModelIndex
关联的新模型元素,这些元素不是线程安全的,并且Qt监视其创建以警告其误用,就像在本例中一样,因为修改该元素是不安全的,因为它意味着从另一个线程修改GUI(请阅读以获取更多信息)

因此,您会看到一条消息,警告您正在尝试的操作是不安全的

相反,
dataChanged
只发出一个信号,不创建任何属于Qt的元素,幸运的是,修改“self.updated”没有产生瓶颈,因为您从辅助线程修改了属于主线程的属性,而没有将保护用作互斥体

Qt指出,GUI和GUI使用的元素只应在GUI线程中更新,如果您想使用其他线程的信息修改GUI,则必须发送该信息,例如,使用线程安全的信号:

随机导入
导入系统
导入线程
导入时间
从PySide2导入QtCore、QtGui、QtWidgets
类TimedModel(QtCore.QAbstractTableModel):
随机_信号=QtCore.signal(对象)
定义初始化(自、表、视图):
super(TimedModel,self)。\uu初始化
self.table=表格
self.view=view
self.setHeaderData(
0,QtCore.Qt.Horizontal,QtCore.Qt.AlignLeft,QtCore.Qt.TextAlignmentRole
)
self.rows=6
self.columns=4
self.step=5
self.updated=set()
self.random\u信号连接(self.random\u插槽)
self.timer=threading.Thread(name=“timer”,target=self.tableTimer,daemon=True)
self.timer.start()
@静力学方法
def编码(行、列):

返回行完成。同时,我将您的解决方案移植到我的实际项目中。就像一首歌。不幸的是,我没有足够的声誉来标记你的答案是有用的。。。