简体   繁体   English

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

[英]PyQt5: phantom columns when using QTableView.setSortingEnabled and QSortFilterProxyModel

I have a custom Qt table model that allows a user to add both columns and rows after it's been created. 我有一个自定义的Qt表模型,允许用户在创建后添加列和行。 I'm trying to display this table using a QSortFilterProxyModel / QTableView setup, but I'm getting strange behavior when I try and enable sorting on the table view. 我正在尝试使用QSortFilterProxyModel / QTableView设置显示此表,但是当我尝试在表视图上启用排序时,我会遇到奇怪的行为。 My view launches and displays the added data correctly: 我的视图启动并正确显示添加的数据:

在发布时查看

However, when I click on one of the column headers (to sort), phantom columns are added to the view. 但是,当我单击其中一个列标题(进行排序)时,幻像列将添加到视图中。

标题点击后查看

Has anyone seen this before or know whats going on? 有没有人见过这个或知道发生了什么? I'm admittedly a novice still with Qt, so maybe I'm just approaching this the wrong way. 我当然是Qt的新手,所以也许我只是接近这个错误的方式。 Thanks. 谢谢。

# -*- 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_()

The Qt documentation is fairly clear on this. Qt文档对此非常清楚。 You must call endInsertRows after beginInsertRows , and endInsertColumns after beginInsertColumns . 你必须调用endInsertRowsbeginInsertRowsendInsertColumnsbeginInsertColumns

The most pertinent point from the last link above is this: 上面最后一个链接中最相关的一点是:

Note: This function emits the columnsAboutToBeInserted() signal which connected views (or proxies) must handle before the data is inserted. 注意:此函数发出columnsAboutToBeInserted()信号,连接的视图(或代理)必须在插入数据之前处理。 Otherwise, the views may end up in an invalid state. 否则,视图可能最终处于无效状态。

So you must call endInsertColum() before beginning any other insertions/deletions. 因此, 开始任何其他插入/删除之前,必须调用endInsertColum()

It looks like the problem was in my SimpleModel.addData method, and is related to how I nested the column and row inserts. 看起来问题出在我的SimpleModel.addData方法中,并且与嵌套列和行插入的方式有关。 If you change this method to first insert new columns, and then insert new rows, the phantom columns don't show up. 如果将此方法更改为首先插入新列,然后插入新行,则不会显示幻像列。

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()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM