Reputation: 150
I use a thread to dynamically increase the data of QTableView, I set up a QSortFilterProxyModel
to filter the data,
but if I click or slide the QTableView program while QThread is running, it will crash, and if I do nothing, QThread can be executed.
I tried self.proxy_model.setDynamicSortFilter(True)
method, but no effect.
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_())
Upvotes: 0
Views: 428
Reputation: 243907
The problem is that you are not adding the items correctly causing that unexpected behavior, although layoutAboutToBeChanged can solve since it indicates that the structure of the model is going to be changed is not the most appropriate but to use the method indicated in the docs:
Considering this case the solution is:
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()
Upvotes: 2