[英]How to sort and filter using QAbstractTableModel instead of QSortFilterProxyModel
I attempt to filter self.items's objects by their self.category
attribute all from inside of QAbstractTableModel
's data() method by comparing this attribute agains a text currently displayed in the QComboBox. 我试图通过比较
self.category
属性的self.category
属性,从QAbstractTableModel
的data()方法内部全部过滤对象,方法是self.category
比较此属性和当前显示在QComboBox中的文本。 Yet, the code doesn't function properly. 但是,代码无法正常运行。
Shouldn't be QAbstractTableModel's data() method used "as a substitute to proxy model's accepts row()
method? 不应该使用QAbstractTableModel的data()方法代替代理模型的
accepts row()
方法吗?
Is it be possible to achieve the filtering without using QSortFilterProxyModel
? 不使用
QSortFilterProxyModel
是否可以实现过滤? If we have to use proxy to filter the model items what would be most Pythonic way of doing this? 如果我们必须使用代理来过滤模型项,最Pythonic的方式是什么?
from PySide import QtGui, QtCore
class Item(object):
def __init__(self):
self.ID=None
self.name=None
self.category=None
class TableModel(QtCore.QAbstractTableModel):
def __init__(self, parent=None):
QtCore.QAbstractTableModel.__init__(self, parent)
self.items = []
self.filterCategory = None
def rowCount(self, parent=QtCore.QModelIndex()):
return len( [item for item in self.items if item.category==self.filterCategory] )
def columnCount(self, parent=QtCore.QModelIndex()):
return 1
def data(self, index, role):
if not index.isValid(): return
row=index.row()
item=self.items[row]
if item.category!=self.filterCategory:
return
if role == QtCore.Qt.DisplayRole:
return self.items[row].name
if role == QtCore.Qt.UserRole:
return self.items[row]
def insertRows(self, row, item, column=1, index=QtCore.QModelIndex()):
self.beginInsertRows(QtCore.QModelIndex(), row, row+1)
self.items.append(item)
self.endInsertRows()
def setFilter(self, comboText):
self.filterCategory = comboText
self.layoutChanged.emit()
def filterAcceptsRow(self, row, proc):
index=self.sourceModel().index(row, 0, proc)
item=self.sourceModel().data(index, QtCore.Qt.UserRole)
if not item: return True
resourceType=item.category
if self.filters.get(category)==False:
return False
if self.searchText and len(self.searchText)>0 and item.searchString(self.searchText)==False:
return False
return True
class MyWindow(QtGui.QWidget):
def __init__(self, *args):
QtGui.QWidget.__init__(self, *args)
vLayout=QtGui.QVBoxLayout(self)
self.setLayout(vLayout)
self.tableModel = TableModel()
self.ViewA=QtGui.QTableView(self)
self.ViewA.clicked.connect(self.viewClicked)
vLayout.addWidget(self.ViewA)
for row in range(5):
item=Item()
item.ID=row
if item.ID%2: item.category='Pet'
else: item.category='Birds'
item.name='%s_%s'%(item.category, row)
self.tableModel.insertRows(row, item)
self.ViewA.setModel(self.tableModel)
self.combo=QtGui.QComboBox()
self.combo.addItems(['Pet','Birds'])
self.combo.activated.connect(self.comboActivated)
vLayout.addWidget(self.combo)
currentComboCategory=self.combo.currentText()
self.tableModel.setFilter(currentComboCategory)
def viewClicked(self, indexClicked):
print('indexClicked() row: %s column: %s'%(indexClicked.row(), indexClicked.column() ))
def comboActivated(self, arg=None):
comboText=self.combo.currentText()
self.tableModel.setFilter(comboText)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
w = MyWindow()
w.show()
sys.exit(app.exec_())
"no-more-proxy" code below shows how to sort and filter from inside of QAbstractTableModel
instead of proxy: 下面的“ no-more-proxy”代码显示了如何从
QAbstractTableModel
内部而不是代理进行排序和过滤:
import sys, os
from PyQt import QtGui, QtCore
class Item(object):
def __init__(self,ID=None,name=None,category=None,area=None):
self.ID=ID
self.name=name
self.category=category
self.area='South'
class TableModel(QtCore.QAbstractTableModel):
def __init__(self, parent=None):
QtCore.QAbstractTableModel.__init__(self, parent)
self.currentItems=[]
self.items = []
self.filterCategory = None
self.searchField = None
self.mainColumn=0
self.order=QtCore.Qt.SortOrder.DescendingOrder
def rowCount(self, parent=QtCore.QModelIndex()):
return len( self.currentItems )
def columnCount(self, parent=QtCore.QModelIndex()):
return 5
def data(self, index, role):
if not index.isValid(): return
row=index.row()
column=index.column()
item=self.currentItems[row]
if role == QtCore.Qt.DisplayRole:
if column==0: return item.ID
elif column==1: return item.name
elif column==2: return item.category
elif column==4 or column==5: return item.area
if role == QtCore.Qt.UserRole:
return item
def insertRows(self, row, item, column=1, index=QtCore.QModelIndex()):
self.beginInsertRows(QtCore.QModelIndex(), row, row+1)
self.items.append(item)
self.endInsertRows()
def setFilter(self, comboText=None, searchText=None, mainColumn=None, order=None):
if comboText: self.filterCategory=comboText
if searchText: self.searchText=searchText
if mainColumn!=None: self.mainColumn=mainColumn
self.order=order
self.currentItems=[item for item in self.items if item.category==self.filterCategory]
if searchText:
self.currentItems=[item for item in self.currentItems if searchText in '%s%s%s'%(item.ID, item.name, item.category)]
values=[]
if self.mainColumn==0: values=[[item.ID, item, False] for item in self.currentItems]
elif self.mainColumn==1: values=[[item.name, item, False] for item in self.currentItems]
elif self.mainColumn==2: values=[[item.category, item, False] for item in self.currentItems]
elif self.mainColumn==3 or self.mainColumn==4: values=[[item.area, item, False] for item in self.currentItems]
keys=sorted([value[0] for value in values if isinstance(value, list)])
if self.order==QtCore.Qt.AscendingOrder: keys=list(reversed(keys))
filtered=[]
for key in keys:
for each in values:
if each[0]!=key: continue
if each[2]==True: continue
item=each[1]
filtered.append(item)
each[2]=True
if filtered: self.currentItems=filtered
self.layoutChanged.emit()
class ItemDelegate(QtGui.QItemDelegate):
def __init__(self, parent):
QtGui.QItemDelegate.__init__(self, parent)
def flags(self, index):
if (index.column() == 1):
return QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled
else:
return QtCore.Qt.ItemIsEnabled
def createEditor(self, parent, option, index):
tableView=parent.parent()
model=tableView.model()
item=model.data(index, QtCore.Qt.UserRole)
combo=QtGui.QComboBox(parent)
combo.addItems(['South','West','North','East'])
combo.currentIndexChanged.connect(self.comboIndexChanged)
if item.area:
comboIndex=combo.findText(item.area)
if comboIndex>=0:
combo.setCurrentIndex(comboIndex)
else: combo.setCurrentIndex(0)
return combo
def comboIndexChanged(self):
self.commitData.emit(self.sender())
def setModelData(self, combo, model, index):
item=model.data(index, QtCore.Qt.UserRole)
comboText=combo.currentText()
item.area=comboText
class MyWindow(QtGui.QWidget):
def __init__(self, *args):
QtGui.QWidget.__init__(self, *args)
vLayout=QtGui.QVBoxLayout(self)
self.setLayout(vLayout)
self.tableModel = TableModel()
self.searchLine=QtGui.QLineEdit()
vLayout.addWidget(self.searchLine)
self.searchLine.textEdited.connect(self.searchLineEditied)
self.searchLine.returnPressed.connect(self.searchLineEditied)
self.tableView=QtGui.QTableView(self)
self.tableView.setSortingEnabled(True)
self.tableView.horizontalHeader().setResizeMode(QtGui.QHeaderView.Stretch)
self.tableView.setShowGrid(False)
self.tableView.setSelectionBehavior(QtGui.QTableView.SelectRows)
self.tableView.setAlternatingRowColors(True)
self.delegate=ItemDelegate(self.tableView)
self.tableView.setItemDelegate(self.delegate)
self.tableView.clicked.connect(self.viewClicked)
vLayout.addWidget(self.tableView)
for row in range(15):
if row%2: category='Pet'
else: category='Birds'
item=Item(category=category, ID=row, name='%s_%s'%(category,row))
self.tableModel.insertRows(row, item)
self.tableView.setModel(self.tableModel)
self.combo=QtGui.QComboBox()
self.combo.addItems(['Pet','Birds'])
self.combo.activated.connect(self.comboActivated)
vLayout.addWidget(self.combo)
currentComboCategory=self.combo.currentText()
self.tableModel.setFilter(currentComboCategory)
self.horizontalHeader=self.tableView.horizontalHeader()
self.horizontalHeader.sortIndicatorChanged.connect(self.headerTriggered)
self.addComboDelegates()
def headerTriggered(self, mainColumn=None, order=None):
self.tableModel.setFilter(mainColumn=mainColumn, order=order)
self.deleteComboDelegates()
self.addComboDelegates()
def comboActivated(self, comboIndex=None):
self.deleteComboDelegates()
comboText=self.combo.currentText()
self.tableModel.setFilter(comboText=comboText)
self.addComboDelegates()
self.tableModel.layoutChanged.emit()
def searchLineEditied(self, searchText=None):
self.tableModel.setFilter(searchText=searchText)
def viewClicked(self, indexClicked):
item=self.tableModel.data(indexClicked, QtCore.Qt.UserRole)
print 'ID: %s, name: %s, category: %s'%(item.ID,item.name,item.category)
def deleteComboDelegates(self):
for row in range(self.tableModel.rowCount()):
index=self.tableModel.index(row, 3, QtCore.QModelIndex())
self.tableView.closePersistentEditor(index)
def addComboDelegates(self):
for row in range(self.tableModel.rowCount()):
index=self.tableModel.index(row, 3, QtCore.QModelIndex())
self.tableView.openPersistentEditor(index)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
w = MyWindow()
w.show()
sys.exit(app.exec_())
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.