2015-08-22 3 views
0

Я пытаюсь отфильтровать объекты self.items по их атрибуту self.category из метода QAbstractTableModel метода данных(), сравнив этот атрибут с текстом, отображаемым в настоящее время в QComboBox. Тем не менее, код не работает должным образом.Как сортировать и фильтровать с помощью QAbstractTableModel вместо QSortFilterProxyModel

не должны быть данные QAbstractTableModel в() метод использовали «в качестве замены accepts row() метода прокси-модели?

ли возможно достичь фильтрации без использования QSortFilterProxyModel? Если мы должны использовать прокси-сервер для фильтрации модели элементы, что было бы наиболее Pythonic способ сделать это?

enter image description here

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

ответ

1

«не-более-прокси» ниже код показывает, как сортировать и фильтровать изнутри QAbstractTableModel вместо прокси:

enter image description here

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_()) 
Смежные вопросы