Use A Qsortfilterproxymodel From Qml With Pyqt5
I try to combine a QML view with a QSortFilterProxyModel within PyQt5. Unfortunately I can't get it to work in any way. My main problem right now seems to be to pass the items bac
Solution 1:
The only way to get it working was to switch to a QAbstractListModel as was suggested by Frank. Here is the important part of the code:
classMyItem(QObject):
nameChanged = pyqtSignal()
def__init__(self, name, parent=None):
QObject.__init__(self, parent)
self._name = name
@pyqtProperty('QString', notify=nameChanged)defname(self):
return self._name
classMyModel(QAbstractListModel):
NameRole = Qt.UserRole + 1
_roles = {NameRole: "name"}
def__init__(self, parent=None):
print("constructing")
super().__init__(parent)
self._items = [MyItem('one'), MyItem('two'), MyItem('three')]
self._column_count = 1defroleNames(self):
print("roleNames")
return self._roles
defrowCount(self, parent=QModelIndex()):
print("rowCount", len(self._items))
returnlen(self._items)
defdata(self, index, role=Qt.DisplayRole):
print("in data")
try:
item = self._items[index.row()]
except IndexError:
return QVariant()
if role == self.NameRole:
return item.name
return QVariant()
and a SortFilterProxyModel which I can use from QML
classSortFilterProxyModel(QSortFilterProxyModel):
def__init__(self, parent):
super().__init__(parent)
@pyqtProperty(QAbstractItemModel)defsource (self):
return self._source
@source.setterdefsource (self, source):
self.setSourceModel(source)
self._source = source
defroleKey(self, role):
roles = self.roleNames()
for key, value in roles.items():
if value == role:
return key
return -1 @pyqtSlot(str, int)defsort(self, role, order):
self.setSortRole(self.roleKey(role));
super().sort(0, order);
Now I can do the following in QML
MyModel {
id:mymodel
}
SortFilterProxyModel {
id:proxyModelsource:mymodel
}
TableView {
id:tableViewanchors.fill:parentmodel:proxyModelsortIndicatorVisible:trueonSortIndicatorOrderChanged:model.sort(getColumn(sortIndicatorColumn).role, sortIndicatorOrder)onSortIndicatorColumnChanged:model.sort(getColumn(sortIndicatorColumn).role, sortIndicatorOrder)TableViewColumn {
title:"Name"role:"name"
}
}
Solution 2:
I now also implemented another way as described here: http://blog.qt.io/blog/2014/04/16/qt-weekly-6-sorting-and-filtering-a-tableview/
The implementation in the SortFilterProxyModel is a bit longer but the QML source gets imho nicer. This version also includes a filter implementation which makes it longer too.
classMyItem(QObject):
nameChanged = pyqtSignal()
def__init__(self, name, parent=None):
QObject.__init__(self, parent)
self._name = name
@pyqtProperty('QString', notify=nameChanged)defname(self):
return self._name
classMyModel(QAbstractListModel):
NameRole = Qt.UserRole + 1
_roles = {NameRole: "name"}
def__init__(self, parent=None):
super().__init__(parent)
self._items = [MyItem('one'), MyItem('two'), MyItem('three')]
self._column_count = 1defroleNames(self):
return self._roles
defrowCount(self, parent=QModelIndex()):
returnlen(self._items)
defdata(self, index, role=Qt.DisplayRole):
try:
item = self._items[index.row()]
except IndexError:
return QVariant()
if role == self.NameRole:
return item.name
return QVariant()
and a SortFilterProxyModel which I can use from QML
classSortFilterProxyModel(QSortFilterProxyModel):
classFilterSyntax:
RegExp, Wildcard, FixedString = range(3)
Q_ENUMS(FilterSyntax)
def__init__(self, parent):
super().__init__(parent)
@pyqtProperty(QAbstractItemModel)defsource(self):
returnsuper().sourceModel()
@source.setterdefsource(self, source):
self.setSourceModel(source)
@pyqtProperty(int)defsortOrder(self):
return self._order
@sortOrder.setterdefsortOrder(self, order):
self._order = order
super().sort(0, order)
@pyqtProperty(QByteArray)defsortRole(self):
return self._roleNames().get(super().sortRole())
@sortRole.setterdefsortRole(self, role):
super().setSortRole(self._roleKey(role))
@pyqtProperty(QByteArray)deffilterRole(self):
return self._roleNames().get(super().filterRole())
@filterRole.setterdeffilterRole(self, role):
super().setFilterRole(self._roleKey(role))
@pyqtProperty(str)deffilterString(self):
returnsuper().filterRegExp().pattern()
@filterString.setterdeffilterString(self, filter):
super().setFilterRegExp(QRegExp(filter, super().filterCaseSensitivity(), self.filterSyntax))
@pyqtProperty(int)deffilterSyntax(self):
returnsuper().filterRegExp().patternSyntax()
@filterSyntax.setterdeffilterSyntax(self, syntax):
super().setFilterRegExp(QRegExp(self.filterString, super().filterCaseSensitivity(), syntax))
deffilterAcceptsRow(self, sourceRow, sourceParent):
rx = super().filterRegExp()
ifnot rx or rx.isEmpty():
returnTrue
model = super().sourceModel()
sourceIndex = model.index(sourceRow, 0, sourceParent)
# skip invalid indexesifnot sourceIndex.isValid():
returnTrue# If no filterRole is set, iterate through all keysifnot self.filterRole or self.filterRole == "":
roles = self._roleNames()
for key, value in roles.items():
data = model.data(sourceIndex, key)
if rx.indexIn(data) != -1:
returnTruereturnFalse# Here we have a filterRole set so only search in that
data = model.data(sourceIndex, self._roleKey(self.filterRole))
return rx.indexIn(data) != -1def_roleKey(self, role):
roles = self.roleNames()
for key, value in roles.items():
if value == role:
return key
return -1def_roleNames(self):
source = super().sourceModel()
if source:
return source.roleNames()
return {}
Now I can do the following in QML
MyModel {
id:mymodel
}
SortFilterProxyModel {
id:proxyModelsource:mymodelsortOrder:tableView.sortIndicatorOrdersortCaseSensitivity:Qt.CaseInsensitivesortRole:tableView.getColumn(tableView.sortIndicatorColumn).rolefilterString:"*"+searchBox.text+"*"filterSyntax:SortFilterProxyModel.WildcardfilterCaseSensitivity:Qt.CaseInsensitivefilterRole:tableView.getColumn(tableView.sortIndicatorColumn).role
}
TableView {
id:tableViewanchors.fill:parentmodel:proxyModelsortIndicatorVisible:trueTableViewColumn {
role:"name"title:"Name"
}
}
Post a Comment for "Use A Qsortfilterproxymodel From Qml With Pyqt5"