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