|  | import sys | 
        
          |  | from PyQt5 import QtCore, QtGui, QtQuick | 
        
          |  |  | 
        
          |  |  | 
        
          |  | class PropertyType(QtCore.pyqtWrapperType): | 
        
          |  | """Metaclass for converting class attributes into pyqtProperties | 
        
          |  |  | 
        
          |  | Usage: | 
        
          |  | >>> class AbstractClass(QtCore.QObject): | 
        
          |  | ...     __metaclass__ = PropertyType | 
        
          |  |  | 
        
          |  | """ | 
        
          |  |  | 
        
          |  | def __new__(cls, name, bases, attrs): | 
        
          |  | for key, value in attrs.copy().items(): | 
        
          |  | if key.startswith("__"): | 
        
          |  | continue | 
        
          |  |  | 
        
          |  | attrs[key] = QtCore.pyqtProperty( | 
        
          |  | type(value), | 
        
          |  | fget=lambda self, x=value: x, | 
        
          |  | constant=True) | 
        
          |  |  | 
        
          |  | return super(PropertyType, cls).__new__(cls, name, bases, attrs) | 
        
          |  |  | 
        
          |  |  | 
        
          |  | class AbstractItem(QtCore.QObject): | 
        
          |  | __metaclass__ = PropertyType | 
        
          |  |  | 
        
          |  |  | 
        
          |  | def Item(**kwargs): | 
        
          |  | """Factory for QAbstractListModel items | 
        
          |  |  | 
        
          |  | Any class attributes are converted into pyqtProperties | 
        
          |  | and must be declared with its type as value. | 
        
          |  |  | 
        
          |  | Usage: | 
        
          |  | >>> item = Item(name="default name", | 
        
          |  | ...             age=5, | 
        
          |  | ...             alive=True) | 
        
          |  | >>> assert item.name == "default name" | 
        
          |  | >>> assert item.age == 5 | 
        
          |  | >>> assert item.alive == True | 
        
          |  | >>> | 
        
          |  | >>> # Jsonifyable content | 
        
          |  | >>> assert item.json == { | 
        
          |  | ...     "name": "default name", | 
        
          |  | ...     "age": 5, | 
        
          |  | ...     "alive": True | 
        
          |  | ...     }, item.json | 
        
          |  |  | 
        
          |  | """ | 
        
          |  |  | 
        
          |  | obj = type("Item", (AbstractItem,), kwargs.copy())() | 
        
          |  | obj.json = kwargs  # Store as json | 
        
          |  | return obj | 
        
          |  |  | 
        
          |  |  | 
        
          |  | class Model(QtCore.QAbstractListModel): | 
        
          |  | def __init__(self, parent=None): | 
        
          |  | super(Model, self).__init__(parent) | 
        
          |  | self.items = [] | 
        
          |  |  | 
        
          |  | def add_item(self, item): | 
        
          |  | self.beginInsertRows(QtCore.QModelIndex(), | 
        
          |  | self.rowCount(), | 
        
          |  | self.rowCount()) | 
        
          |  |  | 
        
          |  | self.items.append(item) | 
        
          |  | self.endInsertRows() | 
        
          |  |  | 
        
          |  | def rowCount(self, parent=QtCore.QModelIndex()): | 
        
          |  | return len(self.items) | 
        
          |  |  | 
        
          |  | def data(self, index, role=QtCore.Qt.DisplayRole): | 
        
          |  | try: | 
        
          |  | return self.items[index.row()] | 
        
          |  | except IndexError: | 
        
          |  | return QtCore.QVariant() | 
        
          |  |  | 
        
          |  | def roleNames(self): | 
        
          |  | return { | 
        
          |  | QtCore.Qt.UserRole: "item" | 
        
          |  | } | 
        
          |  |  | 
        
          |  |  | 
        
          |  | if __name__ == '__main__': | 
        
          |  | import time | 
        
          |  | import doctest | 
        
          |  | doctest.testmod() | 
        
          |  |  | 
        
          |  | def test_performance(): | 
        
          |  | start = time.time() | 
        
          |  | for x in xrange(10000): | 
        
          |  | i = Item(**{"key": "value"}) | 
        
          |  | del(i) | 
        
          |  | end = time.time() | 
        
          |  | print "%.3fs" % (end - start) | 
        
          |  |  | 
        
          |  | test_performance()  # ~0.324s | 
        
          |  |  | 
        
          |  | # Example | 
        
          |  | class Application(QtGui.QGuiApplication): | 
        
          |  | def __init__(self): | 
        
          |  | super(Application, self).__init__(sys.argv) | 
        
          |  |  | 
        
          |  | window = QtQuick.QQuickView() | 
        
          |  | window.setResizeMode(window.SizeRootObjectToView) | 
        
          |  |  | 
        
          |  | window.setWidth(200) | 
        
          |  | window.setHeight(200) | 
        
          |  |  | 
        
          |  | engine = window.engine() | 
        
          |  | engine.addImportPath(".") | 
        
          |  |  | 
        
          |  | model = Model() | 
        
          |  |  | 
        
          |  | # Add a number of items | 
        
          |  | model.add_item(Item(**{"name": "Linus", "color": "brown"})) | 
        
          |  | model.add_item(Item(**{"name": "Snork", "color": "lightgray"})) | 
        
          |  | model.add_item(Item(**{"name": "Belly", "color": "green"})) | 
        
          |  |  | 
        
          |  | for item in model.items: | 
        
          |  | print item.name | 
        
          |  |  | 
        
          |  | context = engine.rootContext() | 
        
          |  | context.setContextProperty("objModel", model) | 
        
          |  |  | 
        
          |  | window.setSource(QtCore.QUrl.fromLocalFile("test.qml")) | 
        
          |  |  | 
        
          |  | window.show() | 
        
          |  |  | 
        
          |  | self.window = window | 
        
          |  | self.model = model | 
        
          |  |  | 
        
          |  | app = Application() | 
        
          |  | app.exec_() |