The removeRows()
works as intended by deleting the selected row.
But there is a problem with insertRows()
. By some reason the new items do not appear at the index-number selected. What causes this problem?
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_())
Mistake was in
insertRows()
method. The incomingrow
argument variable (which is selectedQModelIndex.row()
number) was accidentally re-declared infor loop
:I've renamed the argument
row
variable topostion
and the fixed working code is posted below (theproxyB
sorting attribute was commented out. It displays theViewB
items as unsorted. This way it is easier to see a "real" items order:Edited later:
There was a few more tweaks made to the code. There is a lot happening "behind of scenes": before or after
insertRows()
andremoveRows()
do their job.For example:
When we call these methods the first argument supplied must be a
QModelIndex
's row number. It is going to be used by the methods as a "starting point" or "starting row number" from where the indexes will be added (inserted) or removed: as many as the second integer argument says.As we know the
proxy model
'smodelIndexes
s row and column numbers do not match to the associated with them thesourceModel
's modelIndexes. Interesting but there is a translation fromproxy
's row numbers tosourceModel
's ones before the row-number-argument is even received by those two methods. It can be seen from a print out: thebuttonClicked()
method "sends" row 0 while theinsertRows()
method prints out that it received other than 0 row number (if it was supplied an modelIndex "taken" from by-Proxy-driven TableView with sorting or filtering enabled and active).Aside from it there is some "intricate" mechanism happening on how these two methods remove or pop the data from the
model
'sself.items
variable.removeRows()
method kind of "returns" back to itself to finish a job if the row numbers do not follow in a sequence. The fully working code is posted below: