Search code examples
pythonqmlqtquick2pyside2qabstractlistmodel

Unable to assign CustomModel to QQmlListModel


Suppose we have a list model:

from PySide2.QtCore import Qt, QAbstractListModel, QModelIndex
import numpy as np

class AxisModel(QAbstractListModel):
    MaxRole = Qt.UserRole + 1015
    MinRole = Qt.UserRole + 1016
    TicksRole = Qt.UserRole + 1017

    def __init__(self, min_, max_, price_unit, parent=None):
        super(AxisModel, self).__init__(parent)
        self.max = float(max_)
        self.min = float(min_)
        self.price_unit = float(price_unit)
        self.ticks = np.arange(self.min, self.max + self.price_unit, self.price_unit).tolist()

    def rowCount(self, parent=QModelIndex()):
        if parent.isValid():
            return 0
        return len(self.ticks)

    def data(self, index: QModelIndex, role):
        if 0 > index.row() > self.rowCount() and not index.isValid():
            return None
        if role == AxisModel.MinRole:
            return self.min
        if role == AxisModel.MaxRole:
            return self.max
        if role == AxisModel.TicksRole:
            return self.ticks[index.row()]

    def roleNames(self):
        roles = dict()
        roles[AxisModel.MinRole] = b"min"
        roles[AxisModel.MaxRole] = b"max"
        roles[AxisModel.TicksRole] = b"ticks"
        return roles

This is later used in python code:

(...)
    axismodel = AxisModel(min_=min_, max_=max_, price_unit=0.25)

    app = QGuiApplication(sys.argv)
    view = QQuickView()
    view.setResizeMode(QQuickView.SizeRootObjectToView)
    # register models
    view.rootContext().setContextProperty("axis_model", axismodel)
    view.rootContext().setContextProperty("ts_model", tsmodel) # some other model

    qml_file = os.path.join("/home/user/code/project", "simple_test.qml")
    view.setSource(QUrl.fromLocalFile(os.path.abspath(qml_file)))
    if view.status() == QQuickView.Error:
        sys.exit(-1)
    view.show()

    app.exec_()

The QML file that uses it (simplified):

Item {
    Axis {
        model: axis_model
    }
}

The Axis item:

Item {
    id: axis
    property ListModel model
    property real max: model.max
    property real min: model.min
(...)
}

This produces an error: Unable to assign AxisModel to QQmlListModel

Ok, AxisModel is technically not QQmlListModel, but they both inherit from QAbstractItemModel. I do not know how to resolve this. My two thoughts are:

  1. Use a different type than ListModel in Axis.qml definition. I do not know which one. I tried QObject, QVariant, which turn out not to be QML types. Item does not work as AxisModel is not a QQuickItem instance
  2. Annotate AxisModel class in python code with some PySide2 annotation that would inform QML engine about the type. I have no idea how to approach this.

Thanks for your time.


Solution

  • I think you've correctly identified the problem. Axis model is not a QQmlListModel, so it can't be assigned.

    But you should be able to simply define your model like this:

    property var model