PyQt5:使用 QTableView.setSortingEnabled 和 QSortFilterProxyModel 时的幻像列

PyQt5: phantom columns when using QTableView.setSortingEnabled and QSortFilterProxyModel

我有一个自定义 Qt table 模型,允许用户在创建后添加列和行。我正在尝试使用 QSortFilterProxyModel / QTableView 设置来显示此 table,但是当我尝试在 table 视图上启用排序时,我遇到了奇怪的行为。我的视图启动并正确显示添加的数据:

但是,当我单击其中一列 headers(进行排序)时,幻像列被添加到视图中。

有没有人以前见过这个或知道发生了什么事?诚然,我仍然是 Qt 的新手,所以也许我只是以错误的方式来处理这个问题。谢谢

# -*- mode:python; mode:auto-fill; fill-column:79; coding:utf-8 -*-

from PyQt5.QtCore import *
from PyQt5.QtWidgets import *

# =====================================================================
# =====================================================================
class SimpleProxyModel(QSortFilterProxyModel):
    def filterAcceptsColumn(self, col, index):
        return True

# =====================================================================
# =====================================================================
class SimpleModel(QAbstractTableModel):

    def __init__(self):
        super(SimpleModel, self).__init__()
        self._data = {}

    def rowCount(self, index=QModelIndex()):
        if len(self._data.values()) > 0:
            return len(self._data.values()[0])
        else:
            return 0

    def columnCount(self, index=QModelIndex()):
        return len(self._data.keys())

    def data( self, index, role = Qt.DisplayRole ):
        row, col = index.row(), index.column()

        if ( not index.isValid() or
             not ( 0 <= row < self.rowCount() ) or
             not ( 0 <= col < self.columnCount() ) ):
            return QVariant()

        if role == Qt.DisplayRole:
            return QVariant( self._data[col][row] )

        return QVariant()

    def addData( self, col, val):

        new_col = False
        # Turn on flag for new column
        if col not in self._data.keys():
            new_col = True

        if new_col:
            self.beginInsertColumns(QModelIndex(), self.columnCount(),self.columnCount())
            # Catch this column up with the others by adding blank rows
            self._data[col] = [""] * self.rowCount()

        self.beginInsertRows(QModelIndex(), self.rowCount(), self.rowCount())
        # Add data to each column, either the value specified or a blank
        for i in range(self.columnCount()):
            if i == col:
                self._data[i].append(val)
            else:
                self._data[i].append( "" )
        self.endInsertRows()

        if new_col:
            self.endInsertColumns()


# =====================================================================
# =====================================================================
class SimpleView(QWidget):

    def __init__(self, parent=None):

        super(SimpleView, self).__init__(parent)

        self._mainmodel = None
        self._proxymodel = None
        self._tableview = QTableView()
        self._tableview.setSortingEnabled(True)

        layout = QVBoxLayout()
        layout.addWidget( self._tableview )

        self.setLayout(layout)

    def setModel(self, model):

        self._mainmodel = model
        proxy = SimpleProxyModel()
        proxy.setSourceModel(model)
        self._tableview.setModel(proxy)

# =====================================================================
# =====================================================================
app = QApplication([])

v = SimpleView()
m = SimpleModel()
v.setModel( m )

m.addData(0,1)
m.addData(0,2)
m.addData(1,3)

v.show()
app.exec_()

Qt 文档对此非常清楚。你必须打电话给 endInsertRows after beginInsertRows, and endInsertColumns after beginInsertColumns.

上面最后link最中肯的一点是:

Note: This function emits the columnsAboutToBeInserted() signal which connected views (or proxies) must handle before the data is inserted. Otherwise, the views may end up in an invalid state.

因此您必须在 开始任何其他 insertions/deletions.

之前调用 endInsertColum()

看起来问题出在我的 SimpleModel.addData 方法中,并且与我嵌套列和行插入的方式有关。如果您将此方法更改为先插入新列,然后再插入新行,则不会显示幻像列。

def addData( self, col, val):                                               

    if col not in self._data.keys():                                        
        self.beginInsertColumns(QModelIndex(), self.columnCount(),self.columnCount())
        # Catch this column up with the others by adding blank rows         
        self._data[col] = [""] * self.rowCount()                            
        self.endInsertColumns()                                             

    self.beginInsertRows(QModelIndex(), self.rowCount(), self.rowCount())   
    # Add data to each column, either the value specified or a blank        
    for i in range(self.columnCount()):                                     
        if i == col:                                                        
            self._data[i].append(val)                                       
        else:                                                               
            self._data[i].append( "" )                                      
    self.endInsertRows()