如何在数据变更时全面更新QTableView?
QAbstractTableModel整体数据变更时刷新QTableView的方案
当底层数据出现插入行、删除行、修改行或多种情况并存的变更,且暂时无法追踪具体变更位置时,不需要逐个调用insertRows/deleteRows,可以通过模型的重置通知机制让视图全面刷新。
问题原因
你当前使用dataChanged信号只能通知视图单元格内容的变化,但无法触发视图对行/列数量变更的感知,所以插入新行后视图行数没更新,导致最后一行被截断。
解决方案
使用beginResetModel()和endResetModel()这一对方法:
- 在修改底层数据前调用
beginResetModel(),通知所有关联的视图:模型即将重置,暂停更新 - 修改完数据后调用
endResetModel(),通知视图模型已完成重置,此时视图会重新查询rowCount()、columnCount()以及所有单元格数据,实现全面刷新
修改后的代码示例
import sys from PyQt5 import QtCore, QtWidgets from PyQt5.QtCore import Qt class MyTableModel(QtCore.QAbstractTableModel): def __init__(self): super().__init__() self._data = [ ("spam", "spam", "spam", "spam"), ("spam", "spam", "spam", "spam"), ("spam", "spam", "spam", "spam"), ] def headerData(self, section: int, orientation: Qt.Orientation, role=Qt.DisplayRole): if role == Qt.DisplayRole and orientation == Qt.Horizontal: return f"Foo {section + 1}" def data(self, index, role=Qt.DisplayRole): if role == Qt.DisplayRole: return self._data[index.row()][index.column()] def rowCount(self, parent=QtCore.QModelIndex()): return len(self._data) def columnCount(self, parent=QtCore.QModelIndex()): return 4 def refresh_data(self): # 通知模型即将重置 self.beginResetModel() # 修改底层数据 self._data.insert(0, ("ham", "ham", "ham", "ham")) # 通知模型重置完成,触发视图全面刷新 self.endResetModel() class MainWindow(QtWidgets.QMainWindow): def __init__(self): super().__init__() widget = QtWidgets.QWidget() layout = QtWidgets.QVBoxLayout() widget.setLayout(layout) self.setCentralWidget(widget) self.table = QtWidgets.QTableView() layout.addWidget(self.table) self.model = MyTableModel() self.table.setModel(self.model) update_data_button = QtWidgets.QPushButton("Update data") update_data_button.clicked.connect(self.model.refresh_data) layout.addWidget(update_data_button) app = QtWidgets.QApplication(sys.argv) window = MainWindow() window.show() app.exec_()
补充说明
- 这种方式是全局刷新,会让视图重新加载所有数据,适合你暂时无法追踪细粒度变更的场景
- 后续如果能实现细粒度变更追踪,再改用
insertRows/deleteRows+dataChanged的组合,可以获得更好的性能和更流畅的视图更新效果
内容的提问来源于stack exchange,提问作者PiRK
相关产品推荐
相关产品推荐

