Skip to content

Instantly share code, notes, and snippets.

@congzhangzh
Forked from mottosso/README.md
Created January 31, 2018 14:40
Show Gist options
  • Save congzhangzh/d74073c13ba999090d7f4c4d41aa8b78 to your computer and use it in GitHub Desktop.
Save congzhangzh/d74073c13ba999090d7f4c4d41aa8b78 to your computer and use it in GitHub Desktop.
QObject list-model with factory function

QObject list-model with factory function

image

Same as QObject List Model but with a factory function and arbitrary keys.

See also

API

Items are instantiated like any normal class, it's key-word arguments become PyQt properties.

app.py

item = Item(name="Marcus", color="blue")
assert item.name == "Marcus"
assert item.color == "blue"

From QML, properties are accessed via dot-notation.

app.qml

Text {
   text: item.name
}

And can also be used in QAbstract*Models.

app.qml

ListView {
  model: itemModel  // Context property
  delegate: Text {
    text: item.name
  }
}

See example below for more details.

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_()
import QtQuick 2.3
Rectangle {
color: "steelblue"
anchors.fill: parent
ListView {
anchors.fill: parent
model: objModel
delegate: Text {
text: item.name
color: item.color
font.pixelSize: 50
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment