setModel无法触发modelReset事件的解决方案

前言

在使用PyQt5时,发现setModel无法触发modelReset事件,导致在使用QTableView时,无法动态更新数据。

发现问题

这篇文章的基础上,我们将CustomTableViewMainWindow分离开。

在进一步实现需求的过程中,需要动态更新QStandardItemModel。于是在CustomTableView文件中通过model()获取QStandardItemModel,在MainWindow中直接定义QStandardItemModel便于获取数值。

这样做似乎是没什么问题的,至少在打印地址的时候,无论是model还是model(),地址都是相同的。

但是在后续的过程中我们发现,延时问题依然存在。

例如,我在启动时获得了所有数据存入model,经过一些业务逻辑后筛选出了一些数据,获得了new_model。这个过程成功出发了model.modelReset事件。

在新的业务逻辑需要还原数据的时候,从new_model还原model的过程中,并没能触发model.modelReset事件。

解决方案

实际上解决方案比较简单。如果没能触发,那就手动触发:

1
model().modelReset.emit()

在源码部分,Qt官方并没有做出解释,在QTableView中没有提到setModel的使用方法与modelReset事件的触发过程。

但是呢,相对于直接使用setModel更新数据,官方看起来似乎更推荐使用insertRowsremoveRows来对model进行更新。

以下是官方给定的一个案例。

1
2
3
4
5
6
7
8
def removeRows(self, position, rows, parent):
self.beginRemoveRows(QModelIndex(), position, position+rows-1)

for row in range(0, rows):
del self.stringList[position]

self.endRemoveRows()
return True;

官方的说明是:

The beginRemoveRows() function is always called before any underlying data is removed, and specifies the first and last rows to be removed. This allows other components to access the data before it becomes unavailable. After the rows have been removed, the model emits endRemoveRows() to finish the operation and let other components know that the dimensions of the model have changed.

不难看出,在remove的过程中,model会通过beginRemoveRows()endRemoveRows()两个信号槽告知其他组件,进而做出其他的操作。

所以相对的,不难猜出在setModel的过程中,也是需要显式声明,否则无法触发。