如何在链接到QTableView的模型中插入和删除行

时间:2015-01-29 15:49:57

标签: python qt model pyqt qtableview

removeRows()通过删除选定的行按预期工作。 但是insertRows()存在问题。由于某种原因,新项目不会出现在所选的索引号处。是什么导致了这个问题?

enter image description here

from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys

class Model(QAbstractTableModel):
    def __init__(self, parent=None, *args):
        QAbstractTableModel.__init__(self, parent, *args)
        self.items = ['Item_003','Item_000','Item_005','Item_004','Item_001']
        self.numbers=[20,10,30,50,40]
        self.added=0
    def rowCount(self, parent=QModelIndex()):
        return len(self.items)      
    def columnCount(self, parent=QModelIndex()):
        return 2

    def data(self, index, role):
        if not index.isValid(): return QVariant()
        elif role != Qt.DisplayRole:
            return QVariant()

        row=index.row()
        column=index.column()

        if column==0:
            if row<len(self.items):
                return QVariant(self.items[row])
        elif column==1:
            if row<len(self.numbers):
                return QVariant( self.numbers[row] )
        else:
            return QVariant()

    def removeRows(self, row, rows=1, index=QModelIndex()):
        print "Removing at row: %s"%row
        self.beginRemoveRows(QModelIndex(), row, row + rows - 1)
        self.items = self.items[:row] + self.items[row + rows:]
        self.endRemoveRows()
        return True

    def insertRows(self, row, rows=1, index=QModelIndex()):
        print "Inserting at row: %s"%row
        self.beginInsertRows(QModelIndex(), row, row + rows - 1)
        for row in range(rows):
            self.items.insert(row + row, "New Item %s"%self.added)
            self.added+=1
        self.endInsertRows()
        return True

class Proxy(QSortFilterProxyModel):
    def __init__(self):
        super(Proxy, self).__init__()

class MyWindow(QWidget):
    def __init__(self, *args):
        QWidget.__init__(self, *args)
        vLayout=QVBoxLayout(self)
        self.setLayout(vLayout)

        hLayout=QHBoxLayout()
        vLayout.insertLayout(0, hLayout)

        tableModel=Model(self)               

        proxyA=Proxy()
        proxyA.setSourceModel(tableModel)
        proxyB=Proxy()
        proxyB.setSourceModel(tableModel)

        self.ViewA=QTableView(self)
        self.ViewA.setModel(proxyA)
        self.ViewA.clicked.connect(self.viewClicked)
        self.ViewA.setSortingEnabled(True)
        self.ViewA.sortByColumn(0, Qt.AscendingOrder)


        self.ViewB=QTableView(self) 
        self.ViewB.setModel(proxyB)
        self.ViewB.clicked.connect(self.viewClicked)
        self.ViewB.setSortingEnabled(True)
        self.ViewB.sortByColumn(0, Qt.AscendingOrder)

        hLayout.addWidget(self.ViewA)
        hLayout.addWidget(self.ViewB)

        insertButton=QPushButton('Insert Row Above Selection')
        insertButton.setObjectName('insertButton')
        insertButton.clicked.connect(self.buttonClicked)
        removeButton=QPushButton('Remove Selected Item')
        removeButton.setObjectName('removeButton')
        removeButton.clicked.connect(self.buttonClicked)

        vLayout.addWidget(insertButton)
        vLayout.addWidget(removeButton)


    def viewClicked(self, indexClicked):
        print 'indexClicked() row: %s  column: %s'%(indexClicked.row(), indexClicked.column() )
        proxy=indexClicked.model()

    def buttonClicked(self):
        button=self.sender()
        if not button: return

        tableView=None
        if self.ViewA.hasFocus(): tableView=self.ViewA
        elif self.ViewB.hasFocus(): tableView=self.ViewB
        if not tableView: return

        indexes=tableView.selectionModel().selectedIndexes()

        for index in indexes:
            if not index.isValid(): continue
            if button.objectName()=='removeButton':
                tableView.model().removeRows(index.row(), 1, QModelIndex())

            elif button.objectName()=='insertButton':
                tableView.model().insertRows(index.row(), 1, QModelIndex())

if __name__ == "__main__":
    app = QApplication(sys.argv)
    w = MyWindow()
    w.show()
    sys.exit(app.exec_())

1 个答案:

答案 0 :(得分:1)

错误在于insertRows()方法。传入的row参数变量(选中QModelIndex.row()个数字)在for loop中意外重新声明:

for row in range(rows):

我已将参数row变量重命名为postion,并在下方发布了固定的工作代码(proxyB排序属性已注释掉。它显示ViewB物品未分类。这样就可以更容易地看到“真正的”物品订单:

稍后编辑:

对代码进行了一些调整。有很多事情发生在“幕后”:insertRows()之前或之后removeRows()完成他们的工作。

例如:

当我们调用这些方法时,提供的第一个参数必须是QModelIndex的行号。它将被方法用作“起始点”或“起始行号”,从中添加(插入)或删除索引:与第二个整数参数一样多。

我们知道proxy model的{​​{1}}的行号和列号与它们相关联的modelIndexes的modelIndexes不匹配。有趣的是,在这两个方法甚至收到了row-number-argument之前,有sourceModel的行号到proxy的转换。从打印输出可以看出:sourceModel方法“发送”第0行,而buttonClicked()方法打印出它收到的除0行号之外(如果提供了一个“取自”的modelIndex) by-Proxy驱动的TableView,启用了排序或过滤并激活了它。

除此之外,还有一些“错综复杂”的机制发生在这两种方法如何从insertRows()的{​​{1}}变量中删除或弹出数据。如果行号不在序列中,则model方法将“返回”返回自身以完成作业。 完整工作的代码发布在下面:

enter image description here

self.items