|
from PyQt5 import QtCore |
|
|
|
|
|
class PropertyType(QtCore.pyqtWrapperType): |
|
"""Metaclass for converting class attributes into pyqtProperties |
|
|
|
Usage: |
|
>>> class AbstractClass(QtCore.QObject): |
|
... __metaclass__ = PropertyType |
|
|
|
""" |
|
|
|
prefix = "__pyqtproperty__" |
|
|
|
def __new__(cls, name, bases, attrs): |
|
attrs["type"] = name |
|
properties = list() |
|
|
|
for key, default in attrs.copy().items(): |
|
if key.startswith("__"): |
|
continue |
|
|
|
attrs[key] = QtCore.pyqtProperty( |
|
type(default), |
|
fget=lambda self, k=key, d=default: getattr( |
|
self, cls.prefix + k, d), |
|
constant=True) |
|
|
|
properties.append(key) |
|
|
|
attrs["__pyqtproperties__"] = properties |
|
|
|
return super(PropertyType, cls).__new__(cls, name, bases, attrs) |
|
|
|
|
|
class AbstractItem(QtCore.QObject): |
|
"""Baseclass for QAbstractListModel items |
|
|
|
Any class attributes are converted into pyqtProperties |
|
and must be declared with its type as value. |
|
|
|
..note:: Supports methods and properties, in addition to |
|
class attributes. |
|
|
|
Usage: |
|
>>> class Item(AbstractItem): |
|
... name = "default name" |
|
... age = 10 |
|
... alive = True |
|
... |
|
>>> item = Item(age=5) |
|
>>> assert item.name == "default name" |
|
>>> assert item.age == 5 |
|
>>> assert item.alive == True |
|
|
|
""" |
|
|
|
__metaclass__ = PropertyType |
|
|
|
def __init__(self, **kwargs): |
|
super(AbstractItem, self).__init__() |
|
|
|
for key, value in kwargs.items(): |
|
if hasattr(self, key): |
|
key = PropertyType.prefix + key |
|
setattr(self, key, value) |
|
|
|
|
|
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" |
|
} |
|
|
|
|
|
class MyItem(AbstractItem): |
|
"""Demonstrates the use of AbstractItem""" |
|
name = "default" |
|
color = "purple" |
|
alive = True |
|
|
|
|
|
if __name__ == '__main__': |
|
import sys |
|
from PyQt5 import QtGui, QtQuick |
|
|
|
# Example |
|
class Application(QtGui.QGuiApplication): |
|
def __init__(self): |
|
super(Application, self).__init__(sys.argv) |
|
|
|
window = QtQuick.QQuickView() |
|
window.setResizeMode(window.SizeRootObjectToView) |
|
|
|
window.setWidth(400) |
|
window.setHeight(600) |
|
|
|
engine = window.engine() |
|
engine.addImportPath(".") |
|
|
|
model = Model() |
|
|
|
# Add a number of items |
|
model.add_item(MyItem(name="Linus", color="yellow")) |
|
model.add_item(MyItem(name="Marcus", color="brown")) |
|
model.add_item(MyItem(name="Richard", color="red")) |
|
|
|
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_() |