PyQt5中QSortFilterProxyModel适配增删导出功能的问题
解决QSortFilterProxyModel下QTableView的增删与导出适配问题
问题根源
- 导出报错:
QSortFilterProxyModel仅做数据映射代理,没有你自定义QAbstractTableModel中的print_arraydata方法,直接调用代理模型的该方法必然报错。 - 增删失效:代理模型不存储实际数据,仅负责过滤、排序后的视图映射,所有数据修改操作必须指向源模型(你的自定义模型),直接操作代理模型不会同步源数据,也无法触发视图更新。
具体修复方案
1. 导出功能修复
通过代理模型的sourceModel()方法获取原自定义模型,再调用其print_arraydata方法:
# 错误写法:直接调用代理模型的自定义方法 # self.proxy_model.print_arraydata() # 修复后写法 source_model = self.proxy_model.sourceModel() source_model.print_arraydata()
2. 增删功能修复
新增数据:直接操作源模型
新增数据无需依赖代理索引,直接调用源模型的新增方法,代理会自动同步视图:
# 假设自定义模型有add_data方法 source_model = self.proxy_model.sourceModel() source_model.add_data(["新行列1", "新行列2"])
删除数据:转换代理索引为源模型索引
视图选中的是代理模型的索引,需用mapToSource()转换为源模型索引后再执行删除:
selected_indexes = self.table_view.selectedIndexes() if not selected_indexes: return # 取第一个选中索引(单行删除示例) proxy_index = selected_indexes[0] source_index = self.proxy_model.mapToSource(proxy_index) source_model = self.proxy_model.sourceModel() source_model.delete_data(source_index.row())
完整可运行代码示例
from PyQt5.QtWidgets import (QApplication, QMainWindow, QTableView, QPushButton, QVBoxLayout, QWidget) from PyQt5.QtCore import QAbstractTableModel, QSortFilterProxyModel, Qt class CustomTableModel(QAbstractTableModel): def __init__(self, data=None, parent=None): super().__init__(parent) self._data = data if data else [["Row1 Col1", "Row1 Col2"], ["Row2 Col1", "Row2 Col2"]] self._headers = ["Column 1", "Column 2"] def rowCount(self, parent=None): return len(self._data) def columnCount(self, parent=None): return len(self._headers) def data(self, index, role=Qt.DisplayRole): if role == Qt.DisplayRole: return self._data[index.row()][index.column()] return None def headerData(self, section, orientation, role=Qt.DisplayRole): if role == Qt.DisplayRole and orientation == Qt.Horizontal: return self._headers[section] return None # 自定义导出方法 def print_arraydata(self): print("导出数据:", self._data) # 自定义新增行方法 def add_data(self, row_data): self.beginInsertRows(self.index(0,0), self.rowCount(), self.rowCount()) self._data.append(row_data) self.endInsertRows() # 自定义删除行方法 def delete_data(self, row): if 0 <= row < self.rowCount(): self.beginRemoveRows(self.index(0,0), row, row) del self._data[row] self.endRemoveRows() class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("Proxy Model 适配示例") self.central_widget = QWidget() self.setCentralWidget(self.central_widget) self.layout = QVBoxLayout(self.central_widget) # 初始化源模型与代理模型 self.source_model = CustomTableModel() self.proxy_model = QSortFilterProxyModel() self.proxy_model.setSourceModel(self.source_model) # 绑定代理模型到表格视图 self.table_view = QTableView() self.table_view.setModel(self.proxy_model) self.layout.addWidget(self.table_view) # 功能按钮 self.add_btn = QPushButton("添加行") self.add_btn.clicked.connect(self.add_row) self.layout.addWidget(self.add_btn) self.delete_btn = QPushButton("删除行") self.delete_btn.clicked.connect(self.delete_row) self.layout.addWidget(self.delete_btn) self.export_btn = QPushButton("导出数据") self.export_btn.clicked.connect(self.export_data) self.layout.addWidget(self.export_btn) def add_row(self): new_row = [f"New Row {self.source_model.rowCount()+1} Col1", f"New Row {self.source_model.rowCount()+1} Col2"] self.source_model.add_data(new_row) def delete_row(self): selected_indexes = self.table_view.selectedIndexes() if not selected_indexes: return proxy_index = selected_indexes[0] source_index = self.proxy_model.mapToSource(proxy_index) self.source_model.delete_data(source_index.row()) def export_data(self): self.source_model.print_arraydata() if __name__ == "__main__": app = QApplication([]) window = MainWindow() window.show() app.exec_()
内容的提问来源于stack exchange,提问作者neo
相关产品推荐
相关产品推荐

