You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 21:52:54