2016-04-24 4 views
1

Ich versuche, eine QML-Ansicht mit einem QSortFilterProxyModel innerhalb PyQt5 zu kombinieren. Leider kann ich es in keiner Weise zur Arbeit bringen. Mein Hauptproblem scheint jetzt zu sein, die Artikel von QML zurückzugeben. Aber selbst wenn das möglich wäre, scheint es, dass es nicht funktioniert, ich bekomme TypeError: QSortFilterProxyModel.setSourceModel(QAbstractItemModel): argument 1 has unexpected type 'PyCapsule', wenn ich das Modell direkt in Python setze.Verwenden Sie ein QSortFilterProxyModel von QML mit PyQt5

Zur Zeit habe ich:

class SortFilterProxyModel(QSortFilterProxyModel): 

    @pyqtProperty(QQmlListReference) 
    def source (self): 
     return self._source 

    @source.setter 
    def source (self, source): 
     setSourceModel(source) 
     self._source = source 


class MyItem(QObject): 

    nameChanged = pyqtSignal() 

    def __init__(self, name, parent=None): 
     QObject.__init__(self, parent) 
     self._name = name 

    @pyqtProperty('QString', notify=nameChanged) 
    def name(self): 
     return self._name 


class MyModel(QObject): 

    itemsChanged = pyqtSignal() 

    def __init__(self, parent=None): 
     QObject.__init__(self, parent) 
     self._items = [MyItem('one'), MyItem('two'), MyItem('three')] 

    @pyqtProperty(QQmlListProperty, notify=itemsChanged) 
    def items(self): 
     print('Query for items') 
     return QQmlListProperty(MyItem, self, self._items) 

    @pyqtSlot() 
    def new_item(self): 
     print('Append new item') 
     self._items.append(MyItem('new')) 
     self.itemsChanged.emit() 

und

import QtQuick 2.2 
import QtQuick.Layouts 1.1 
import QtQuick.Controls 1.2 
import QtQuick.Dialogs 1.2 
import MyModel 1.0 
import MyItem 1.0 
import SortFilterProxyModel 1.0 

ApplicationWindow { 

    function getCurrentIndex(list, element) { 
     console.log('getCurrentIndex') 
     if (list && element) { 
      for (var i = 0; i < list.length; i++) { 
       if (list[i].name === element.name) { 
        console.log('Found item at pos: ' + i) 
        return i 
       } 
      } 
     } 
     return -1 
    } 

    id: mainWindow 
    width: 800; height: 600 
    color: "gray" 

    MyModel { 
     id: mymodel 
    } 

    SortFilterProxyModel { 
     id: proxyModel 
     source: mymodel.items 
    } 

    TableView { 
     anchors.fill: parent 
     //model: mymodel.items 
     model: proxyModel 
     TableViewColumn { 
      role: "name" 
      title: "Name" 
     } 
    } 

} 

volle Quelle hier:

https://github.com/sturmf/python_samples/tree/master/pyqt_qsortfilterproxymodel

+0

das Quellmodell eines QSortFilterProxyModel tun muss ein QAbstractItemModel sein, von denen QQmlListProperty und QQmlListReference stammen nicht von –

Antwort

0

ich jetzt auch anders implementiert als hier beschrieben: http://blog.qt.io/blog/2014/04/16/qt-weekly-6-sorting-and-filtering-a-tableview/

Die Implementierung in der Sort FilterProxyModel ist ein bisschen länger, aber die QML-Quelle wird im- mer schöner. Diese Version enthält auch eine Filterimplementierung , die es auch länger macht.

class MyItem(QObject): 

    nameChanged = pyqtSignal() 

    def __init__(self, name, parent=None): 
     QObject.__init__(self, parent) 
     self._name = name 

    @pyqtProperty('QString', notify=nameChanged) 
    def name(self): 
     return self._name 


class MyModel(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 = 1 

    def roleNames(self): 
     return self._roles 

    def rowCount(self, parent=QModelIndex()): 
     return len(self._items) 

    def data(self, index, role=Qt.DisplayRole): 
     try: 
      item = self._items[index.row()] 
     except IndexError: 
      return QVariant() 

     if role == self.NameRole: 
      return item.name 

     return QVariant() 

und ein SortFilterProxyModel, die ich von QML kann

class SortFilterProxyModel(QSortFilterProxyModel): 

    class FilterSyntax: 
     RegExp, Wildcard, FixedString = range(3) 

    Q_ENUMS(FilterSyntax) 

    def __init__(self, parent): 
     super().__init__(parent) 

    @pyqtProperty(QAbstractItemModel) 
    def source(self): 
     return super().sourceModel() 

    @source.setter 
    def source(self, source): 
     self.setSourceModel(source) 

    @pyqtProperty(int) 
    def sortOrder(self): 
     return self._order 

    @sortOrder.setter 
    def sortOrder(self, order): 
     self._order = order 
     super().sort(0, order) 

    @pyqtProperty(QByteArray) 
    def sortRole(self): 
     return self._roleNames().get(super().sortRole()) 

    @sortRole.setter 
    def sortRole(self, role): 
     super().setSortRole(self._roleKey(role)) 

    @pyqtProperty(QByteArray) 
    def filterRole(self): 
     return self._roleNames().get(super().filterRole()) 

    @filterRole.setter 
    def filterRole(self, role): 
     super().setFilterRole(self._roleKey(role)) 

    @pyqtProperty(str) 
    def filterString(self): 
     return super().filterRegExp().pattern() 

    @filterString.setter 
    def filterString(self, filter): 
     super().setFilterRegExp(QRegExp(filter, super().filterCaseSensitivity(), self.filterSyntax)) 

    @pyqtProperty(int) 
    def filterSyntax(self): 
     return super().filterRegExp().patternSyntax() 

    @filterSyntax.setter 
    def filterSyntax(self, syntax): 
     super().setFilterRegExp(QRegExp(self.filterString, super().filterCaseSensitivity(), syntax)) 

    def filterAcceptsRow(self, sourceRow, sourceParent): 
     rx = super().filterRegExp() 
     if not rx or rx.isEmpty(): 
      return True 
     model = super().sourceModel() 
     sourceIndex = model.index(sourceRow, 0, sourceParent) 
     # skip invalid indexes 
     if not sourceIndex.isValid(): 
      return True 
     # If no filterRole is set, iterate through all keys 
     if not self.filterRole or self.filterRole == "": 
      roles = self._roleNames() 
      for key, value in roles.items(): 
       data = model.data(sourceIndex, key) 
       if rx.indexIn(data) != -1: 
        return True 
      return False 
     # Here we have a filterRole set so only search in that 
     data = model.data(sourceIndex, self._roleKey(self.filterRole)) 
     return rx.indexIn(data) != -1 

    def _roleKey(self, role): 
     roles = self.roleNames() 
     for key, value in roles.items(): 
      if value == role: 
       return key 
     return -1 

    def _roleNames(self): 
     source = super().sourceModel() 
     if source: 
      return source.roleNames() 
     return {} 

Jetzt kann ich folgend in QML

MyModel { 
    id: mymodel 
} 

SortFilterProxyModel { 
    id: proxyModel 
    source: mymodel 

    sortOrder: tableView.sortIndicatorOrder 
    sortCaseSensitivity: Qt.CaseInsensitive 
    sortRole: tableView.getColumn(tableView.sortIndicatorColumn).role 

    filterString: "*" + searchBox.text + "*" 
    filterSyntax: SortFilterProxyModel.Wildcard 
    filterCaseSensitivity: Qt.CaseInsensitive 
    filterRole: tableView.getColumn(tableView.sortIndicatorColumn).role 
} 

TableView { 
    id: tableView 
    anchors.fill: parent 
    model: proxyModel 
    sortIndicatorVisible: true 
    TableViewColumn { 
     role: "name" 
     title: "Name" 
    } 
} 
0

Der einzige Weg, um es zu bekommen war Arbeit zu einem QAbstractListModel wechseln als wurde von Frank vorgeschlagen. Hier ist der wichtige Teil des Codes:

class MyItem(QObject): 

    nameChanged = pyqtSignal() 

    def __init__(self, name, parent=None): 
     QObject.__init__(self, parent) 
     self._name = name 

    @pyqtProperty('QString', notify=nameChanged) 
    def name(self): 
     return self._name 

class MyModel(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 = 1 

    def roleNames(self): 
     print("roleNames") 
     return self._roles 

    def rowCount(self, parent=QModelIndex()): 
     print("rowCount", len(self._items)) 
     return len(self._items) 

    def data(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() 

und ein SortFilterProxyModel, die ich von QML können

class SortFilterProxyModel(QSortFilterProxyModel): 

    def __init__(self, parent): 
     super().__init__(parent) 

    @pyqtProperty(QAbstractItemModel) 
    def source (self): 
     return self._source 

    @source.setter 
    def source (self, source): 
     self.setSourceModel(source) 
     self._source = source 

    def roleKey(self, role): 
     roles = self.roleNames() 
     for key, value in roles.items(): 
      if value == role: 
       return key 
     return -1 

    @pyqtSlot(str, int) 
    def sort(self, role, order): 
     self.setSortRole(self.roleKey(role)); 
     super().sort(0, order); 

Jetzt kann ich in QML Folgendes tun

MyModel { 
    id: mymodel 
} 

SortFilterProxyModel { 
    id: proxyModel 
    source: mymodel 
} 

TableView { 
    id: tableView 
    anchors.fill: parent 
    model: proxyModel 
    sortIndicatorVisible: true 
    onSortIndicatorOrderChanged: model.sort(getColumn(sortIndicatorColumn).role, sortIndicatorOrder) 
    onSortIndicatorColumnChanged: model.sort(getColumn(sortIndicatorColumn).role, sortIndicatorOrder) 
    TableViewColumn { 
     title: "Name" 
     role: "name" 
    } 
}