Reputation: 79
I am a beginner in python and qt. I need to sort QAbstractList created in python by one attribute of list.I used sorted() method .But when i run the code python stops working.can u help.From Qml I called the slot sortData() .sortData() function is not correct i think my code is
model2.py
from PyQt5.QtCore import QAbstractListModel, Qt, pyqtSignal, pyqtSlot
from PyQt5.QtCore import QSortFilterProxyModel
class PersonModel(QAbstractListModel):
Name = Qt.UserRole + 1
value1 = Qt.UserRole + 2
value2 = Qt.UserRole + 3
value3 = Qt.UserRole + 4
value4 = Qt.UserRole + 5
personChanged = pyqtSignal()
def __init__(self, parent=None):
super().__init__(parent)
self.persons = [
{'name': 'item1', 'value1': 10.66, 'value2':10.78, 'value3':10.94, 'value4':10.90},
{'name': 'item1', 'value1': 10.56, 'value2':10.78, 'value3':10.34, 'value4':10.90},
{'name': 'item2', 'value1': 10.66, 'value2':10.88, 'value3':10.44, 'value4':10.30}
]
self.i=0
print(self.persons)
def data(self, QModelIndex, role):
row = QModelIndex.row()
if role == self.Name:
return self.persons[row]['name']
if role == self.value1:
return self.persons[row]['value1']
if role == self.value2:
return self.persons[row]['value2']
if role == self.value3:
return self.persons[row]['value3']
if role == self.value4:
return self.persons[row]['value4']
def rowCount(self, parent=None):
return len(self.persons)
def roleNames(self):
return {
Qt.UserRole + 1: b'name',
Qt.UserRole + 2: b'value1',
Qt.UserRole + 3: b'value2',
Qt.UserRole + 4: b'value3',
Qt.UserRole + 5: b'value4'
}
@pyqtSlot()
def addData(self):
self.beginResetModel()
self.persons = self.persons.append({'name': 'peter', 'value1': 22, 'value2':30, 'value3':40, 'value4':50})
self.endResetModel()
print(self.persons)
@pyqtSlot()
def editData(self):
print(self.model.persons)
@pyqtSlot(int)
def sortData(self):
self.beginResetModel()
self.persons = sorted(self.persons, key=lambda x: float(x[1]))
sorted(self.persons)
#sorted_x = sorted(self._persons, key=lambda role: self.value1)
#print(sorted_x)
#self.persons.sort(2, key=Qt.AscendingOrder)
self.endResetModel()
print(self.persons)
Hello.py
import sys, model2
from PyQt5.QtCore import QUrl
from PyQt5.QtWidgets import QApplication
from PyQt5.QtQuick import QQuickView
from PyQt5.QtCore import QSortFilterProxyModel
from os import path
import PyQt5
import sys, model2
from PyQt5.QtCore import *
from PyQt5.QtCore import pyqtProperty, QObject, pyqtSignal
from PyQt5.QtGui import QGuiApplication
from PyQt5.QtQml import QQmlApplicationEngine
from PyQt5.QtCore import pyqtProperty, QCoreApplication, QObject, QUrl
from PyQt5.QtQml import qmlRegisterType, QQmlComponent, QQmlEngine, QQmlListProperty
from PyQt5.QtCore import QTimer, pyqtSignal,pyqtSlot
from PyQt5.QtQml import QQmlListProperty
import sys, model2
from PyQt5.QtCore import QUrl
from PyQt5.QtWidgets import QApplication
from PyQt5.QtQuick import QQuickView
#import QSortFilterProxyModel
import imageResources
import fontResources
class MainWindow(QQuickView):
def __init__(self, parent=None):
super().__init__(parent)
self.model = model2.PersonModel()
self.proxyModel = QSortFilterProxyModel();
self.proxyModel.setSourceModel(self.model)
self.rootContext().setContextProperty('PersonModel', self.model)
self.rootContext().setContextProperty('MainWindow', self)
self.proxyModel.sort(2,Qt.AscendingOrder)
self.setSource(QUrl('main.qml'))
myApp = QApplication(sys.argv)
ui = MainWindow()
ui.show()
sys.exit(myApp.exec_())
From Qml I called the slot sortData() .sortData() function is not correct i think
Upvotes: 1
Views: 639
Reputation: 243907
To order the view the most appropriate option is to use QSortProxyModel but this will only work from the Python side, if we want to expose that method to QML we must make some modifications so create a class that inherits from QSortProxyModel and add that method:
class SortProxyModel(QSortFilterProxyModel):
@pyqtSlot(str, Qt.SortOrder)
def sortData(self, roleName, order):
if order == Qt.InitialSortOrderRole:
self.setSortRole(order)
self.invalidate()
else:
roles = [key for key, value in self.roleNames().items() if value == roleName.encode()]
if len(roles) > 0:
self.setSortRole(roles[0])
self.sort(0, order)
Then what you have to do is pass as the base the original model through setSourceModel()
, and this new model is what you must pass to qml.
if __name__ == '__main__':
myApp = QGuiApplication(sys.argv)
engine = QQmlApplicationEngine()
model = PersonModel()
proxyModel = SortProxyModel()
proxyModel.setSourceModel(model)
engine.rootContext().setContextProperty('mymodel', proxyModel)
engine.load(QUrl.fromLocalFile(QDir.current().absoluteFilePath('main.qml')))
if len(engine.rootObjects()) == 0:
sys.exit(-1)
sys.exit(myApp.exec_())
In the following link there is an example
Upvotes: 1