使用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()
我用线程动态增加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()