使用QSortFilterProxyModel动态过滤数据程序崩溃

Use QSortFilterProxyModel to dynamically filter data program crashes

我用线程动态增加QTableView的数据,我设置了一个QSortFilterProxyModel来过滤数据, 但是如果我在QThread运行的时候点击或者滑动QTableView程序就会崩溃,如果我什么都不做,QThread是可以执行的

我尝试了self.proxy_model.setDynamicSortFilter(True)方法,但没有效果。

import sys, time
from PyQt5 import QtWidgets
from PyQt5 import QtCore
from PyQt5.QtCore import Qt

class QThreadSender(QtCore.QThread):
    sig_send_data = QtCore.pyqtSignal(object)

    def __init__(self, datas, parent=None):
        super(QThreadSender, self).__init__(parent)
        self.datas = datas

    def run(self):
        for data in self.datas:
            time.sleep(0.05)
            self.sig_send_data.emit(data)

class TableModel(QtCore.QAbstractTableModel):
    def __init__(self, datas):
        super(TableModel, self).__init__()
        self._datas = datas

    def data(self, index, role=None):
        if role == Qt.DisplayRole:
            return self._datas[index.row()][index.column()]

    def rowCount(self, parent=None, *args, **kwargs):
        return len(self._datas)

    def columnCount(self, parent=None, *args, **kwargs):
        if self._datas:
            return len(self._datas[0])
        else:
            return 0

class MainWidget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(MainWidget, self).__init__(parent)
        self.datas = []

        self.model = TableModel(self.datas)
        self.proxy_model = QtCore.QSortFilterProxyModel()
        # self.proxy_model.setDynamicSortFilter(True)
        self.proxy_model.setSourceModel(self.model)
        self.proxy_model.setFilterRegExp(QtCore.QRegExp('a1|a3'))
        self.proxy_model.setFilterKeyColumn(0)
        self.proxy_model.setDynamicSortFilter(True)

        self.treeview = QtWidgets.QTableView()
        self.treeview.setModel(self.proxy_model)
        self.btn = QtWidgets.QPushButton("Run")
        self.btn.clicked.connect(self.slot_send_data)
        layout = QtWidgets.QVBoxLayout(self)
        layout.addWidget(self.treeview)
        layout.addWidget(self.btn)

    def slot_send_data(self):
        datas = [('a1', 'b1', 'c'), ('a2', 'b1', 'c'), ('a3', 'b1', 'c'), ('a4', 'b1', 'c')]*25
        self.t = QThreadSender(datas)
        self.t.sig_send_data.connect(self.slot_update_data)
        self.t.start()

    def slot_update_data(self, data):
        self.datas.append(data)
        self.model.layoutChanged.emit()
        self.treeview.scrollToBottom()

app = QtWidgets.QApplication(sys.argv)
main = MainWidget()
main.show()
sys.exit(app.exec_())

问题是您没有正确添加项目导致意外行为,尽管 layoutAboutToBeChanged 可以解决,因为它表明将要更改的模型结构不是最合适的,但请使用指示的方法在 the docs:

考虑到这种情况,解决方案是:

class TableModel(QtCore.QAbstractTableModel):
    def __init__(self, datas):
        super(TableModel, self).__init__()
        self._datas = datas

    def data(self, index, role=Qt.DisplayRole):
        if role == Qt.DisplayRole:
            return self._datas[index.row()][index.column()]

    def rowCount(self, parent=QtCore.QModelIndex()):
        return len(self._datas)

    def columnCount(self, parent=QtCore.QModelIndex()):
        if self._datas:
            return len(self._datas[0])
        else:
            return 0

    def append(self, data):
        f = len(data) > self.columnCount()
        if f:
            self.beginInsertColumns(
                QtCore.QModelIndex(), self.columnCount(), len(data) - 1
            )
        self.beginInsertRows(QtCore.QModelIndex(), self.rowCount(), self.rowCount())
        
        self._datas.append(data)
        
        self.endInsertRows()
        if f:
            self.endInsertColumns()
def slot_update_data(self, data):
    self.model.append(data)
    self.treeview.scrollToBottom()