如何从链接到QTableView的模型中插入和删除行 [英] How to insert and remove row from model linked to QTableView
问题描述
removeRows()
通过删除选定的行按预期工作.
但是insertRows()
存在问题.由于某些原因,新项目不会出现在所选索引编号处.是什么原因导致这个问题?
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在insertRows()
方法中.传入的row
自变量(在QModelIndex.row()
号中选择)是在for loop
中意外地重新声明的:
Mistake was in insertRows()
method. The incoming row
argument variable (which is selected QModelIndex.row()
number) was accidentally re-declared in for loop
:
for row in range(rows):
我将参数row
变量重命名为postion
,固定的工作代码发布在下面(proxyB
排序属性被注释掉.它显示ViewB
项为未排序.这种方式是更容易看到真实"物品订单:
I've renamed the argument row
variable to postion
and the fixed working code is posted below (the proxyB
sorting attribute was commented out. It displays the ViewB
items as unsorted. This way it is easier to see a "real" items order:
还对代码进行了一些调整. 幕后"发生了很多事情:insertRows()
和removeRows()
进行工作之前或之后.
There was a few more tweaks made to the code. There is a lot happening "behind of scenes": before or after insertRows()
and removeRows()
do their job.
例如:
当我们调用这些方法时,提供的第一个参数必须是QModelIndex
的行号.方法将使用它作为起点"或起点行号",从该起点添加(插入)或删除索引:与第二个整数参数说的一样多.
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.
我们知道proxy model
的modelIndexes
的行号和列号与sourceModel
的modelIndexes关联的行号和列号不匹配.有趣的是,在这两种方法甚至没有接收到行号参数之前,还有从proxy
的行号到sourceModel
的行号的转换.从打印输出中可以看出:buttonClicked()
方法发送"第0行,而insertRows()
方法打印出接收到的不是0行号(如果它是从by-Proxy-驱动的TableView启用了排序或过滤功能并处于活动状态).
As we know the proxy model
's modelIndexes
s row and column numbers do not match to the associated with them the sourceModel
's modelIndexes. Interesting but there is a translation from proxy
's row numbers to sourceModel
's ones before the row-number-argument is even received by those two methods. It can be seen from a print out: the buttonClicked()
method "sends" row 0 while the insertRows()
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).
除此以外,这两种方法如何从model
的self.items
变量中删除或弹出数据还有一些复杂"的机制.如果行号未按顺序排列,则removeRows()
方法会返回"自身以完成作业.
完整的工作代码如下:
Aside from it there is some "intricate" mechanism happening on how these two methods remove or pop the data from the model
's self.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:
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_A000','Item_B001','Item_A002','Item_B003','Item_B004']
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, position, rows=1, index=QModelIndex()):
print "\n\t\t ...removeRows() Starting position: '%s'"%position, 'with the total rows to be deleted: ', rows
self.beginRemoveRows(QModelIndex(), position, position + rows - 1)
self.items = self.items[:position] + self.items[position + rows:]
self.endRemoveRows()
return True
def insertRows(self, position, rows=1, index=QModelIndex()):
print "\n\t\t ...insertRows() Starting position: '%s'"%position, 'with the total rows to be inserted: ', rows
indexSelected=self.index(position, 0)
itemSelected=indexSelected.data().toPyObject()
self.beginInsertRows(QModelIndex(), position, position + rows - 1)
for row in range(rows):
self.items.insert(position + row, "%s_%s"% (itemSelected, self.added))
self.added+=1
self.endInsertRows()
return True
class Proxy(QSortFilterProxyModel):
def __init__(self):
super(Proxy, self).__init__()
def filterAcceptsRow(self, rowProc, parentProc):
modelIndex=self.sourceModel().index(rowProc, 0, parentProc)
item=self.sourceModel().data(modelIndex, Qt.DisplayRole).toPyObject()
if item and 'B' in item:
return True
else: return False
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)
proxyB=Proxy()
proxyB.setSourceModel(tableModel)
self.ViewA=QTableView(self)
self.ViewA.setModel(tableModel)
self.ViewA.clicked.connect(self.viewClicked)
self.ViewB=QTableView(self)
self.ViewB.setModel(proxyB)
self.ViewB.clicked.connect(self.viewClicked)
self.ViewB.setSortingEnabled(True)
self.ViewB.sortByColumn(0, Qt.AscendingOrder)
self.ViewB.setSelectionBehavior(QTableView.SelectRows)
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 getZeroColumnSelectedIndexes(self, tableView=None):
if not tableView: return
selectedIndexes=tableView.selectedIndexes()
if not selectedIndexes: return
return [index for index in selectedIndexes if not index.column()]
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: print 'buttonClicked(): not tableView'; return
zeroColumnSelectedIndexes=self.getZeroColumnSelectedIndexes(tableView)
if not zeroColumnSelectedIndexes: print 'not zeroColumnSelectedIndexes'; return
firstZeroColumnSelectedIndex=zeroColumnSelectedIndexes[0]
if not firstZeroColumnSelectedIndex or not firstZeroColumnSelectedIndex.isValid():
print 'buttonClicked(): not firstZeroColumnSelectedIndex.isValid()'; return
startingRow=firstZeroColumnSelectedIndex.row()
print '\n buttonClicked() startingRow =', startingRow
if button.objectName()=='removeButton':
tableView.model().removeRows(startingRow, len(zeroColumnSelectedIndexes), QModelIndex())
elif button.objectName()=='insertButton':
tableView.model().insertRows(startingRow, len(zeroColumnSelectedIndexes), QModelIndex())
if __name__ == "__main__":
app = QApplication(sys.argv)
w = MyWindow()
w.show()
sys.exit(app.exec_())
这篇关于如何从链接到QTableView的模型中插入和删除行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!