Python 无法将CustomModel分配给QQmlListModel

Python 无法将CustomModel分配给QQmlListModel,python,qml,qtquick2,pyside2,qabstractlistmodel,Python,Qml,Qtquick2,Pyside2,Qabstractlistmodel,假设我们有一个列表模型: 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_

假设我们有一个列表模型:

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
这稍后将在python代码中使用:

(...)
    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_()
使用它的QML文件(简化):

轴项目:

Item {
    id: axis
    property ListModel model
    property real max: model.max
    property real min: model.min
(...)
}
这会产生一个错误:
无法将AxisModel分配给QQmlListModel

好的,AxisModel在技术上不是QQmlListModel,但它们都继承自QBStractItemModel。我不知道如何解决这个问题。我的两个想法是:

  • 使用与Axis.qml定义中的
    ListModel
    不同的类型。我不知道是哪一个。我试过QObject,QVariant,结果不是QML类型。项不工作,因为AxisModel不是QQuickItem实例
  • 用一些PySide2注释在python代码中注释AxisModel类,该注释将通知QML引擎该类型。我不知道该怎么做

  • 谢谢您的时间。

    我想您已经正确地识别了问题。Axis模型不是QQmlListModel,因此无法指定它

    但您应该能够像这样简单地定义您的模型:

    property var model
    

    为了补充已被接受的答案,以下是使其生效所需的更改

    轴项目-使用
    var
    让QML自行决定类型:

    Item {
        id: axis
        property var model
        property var min
        property var max
    (...)
    }
    
    在QML中调用axis项:

    Item {
    
        AxisTest {
            model: axis_model
            min: axis_model.min
            max: axis_model.max
        }
    (...)
    }
    
    然后,在python中:

  • 删除最小/最大角色

  • 为每个属性定义getter、setter和change信号(我仍然不知道该信号应该做什么,所以现在就到此为止)

  • 在类(而不是实例)上注册一个属性,其中绑定了getter、setter和notification signal

  • 在构造函数中设置每个属性的初始值


  • 就这样!至少对于模型零件。我仍然无法使用
    model.max
    访问最小/最大字段。这使得
    无法将[undefined]分配给QString
    ,这很奇怪,因为min和max都是浮点数,应该可以工作。
    min
    max
    是模型中的角色,而不是模型本身的属性。这意味着列表中的每个项目都有自己的最小值和最大值。哎呀。看来我严重误解了这一点。你能给我指一下这里的正确方向吗?我如何将min和max定义为模型上的属性?我不是python爱好者,所以我不知道适合您的语法。我将从对属性的基本理解开始,然后也许可以解释如何在python中使用它。
    Item {
    
        AxisTest {
            model: axis_model
            min: axis_model.min
            max: axis_model.max
        }
    (...)
    }
    
    class AxisModel(QAbstractListModel):
        def get_min(self):
            return self._min
    
        def set_min(self, _min):
            self._min = _min
    
        def get_max(self):
            return self._max
    
        def set_max(self, _max):
            self._max = _max
    
        @Signal
        def max_changed(self, _max):
            pass
    
        @Signal
        def min_changed(self, _min):
            pass
    
        TicksRole = Qt.UserRole + 1015
        max = Property(float, get_max, set_max, notify=max_changed)
        min = Property(float, get_min, set_min, notify=min_changed)
    
        def __init__(self, min_, max_, price_unit, parent=None):
            super(AxisModel, self).__init__(parent)
            self._max = float(max_)
            self._min = float(min_)
            self.ticks = np.arange(float(min_), float(max_) + float(price_unit), float(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.TicksRole:
                return self.ticks[index.row()]
            else:
                return None
    
        def roleNames(self):
            roles = dict()
            roles[AxisModel.TicksRole] = b"ticks"
            return roles