QML更新Json模型

QML更新Json模型,json,qt,qml,Json,Qt,Qml,我有一个QT,它的gui是用QML创建的。我正在使用一个自定义组件,它使用一个模型来显示数据。在运行时,此模型将发生更改。然而,这些变化并未反映出来 MyCustomComponent { property var myModel: [ { icon: "qrc:/resources/my_icon1.png", data: "Initial text", }, { i

我有一个QT,它的gui是用QML创建的。我正在使用一个自定义组件,它使用一个模型来显示数据。在运行时,此模型将发生更改。然而,这些变化并未反映出来

MyCustomComponent
{
    property var myModel: [
        {
            icon: "qrc:/resources/my_icon1.png",
            data: "Initial text",
        },
        {
            icon: "qrc:/resources/my_icon2.png",
            data: "Initial text",
        }
    ]
    model: myModel

    property int myProp: 0

    onMyPropChanged:
    {
        refreshModel()
    }

    function refreshModel()
    {
        console.error("refreshModel: before: myModel:" + myModel[0].data +  ", model:" + model[0].data);
        myModel[0].data = "alternate text"
        console.error("refreshModel: after: myModel:" + myModel[0].data +  ", model:" + model[0].data);
    }
}
结果:

refreshModel: before: myModel:Initial text, model:Initial text
refreshModel: after: myModel:alternate text, model:Initial text
因此,在运行时,
myProp
发生更改时,将调用
refreshModel
。然而,
模型
本身保持不变,
myModel
确实发生了变化

直接更改模型而不更改也不起作用。(因此,删除myModel中间的属性)

我需要做什么不同的事情

旁注:
最初我使用的是
ListModel
+
ListElement
,但这还有其他问题,我正在寻找替代的
(ListElement:cannot use script for property value)

事实上,修改myModel结构不会触发信号。我习惯了这种模式,它的优点是使用不可变的结构:

MyCustomComponent
{
    function computeModel(initial)
    {
        return [
            {
                icon: "qrc:/resources/my_icon1.png",
                data: initial ? "Initial text" : "alternate text",
            },
            {
                icon: "qrc:/resources/my_icon2.png",
                data: "Initial text",
            }
        ];
    }
    model: computeModel(true)

    property int myProp: 0

    onMyPropChanged:
    {
        model = computeModel(false);
    }
}

看看Qt文档中关于的内容

需要注意的是,分配给var属性的JavaScript对象的常规属性的更改不会触发访问它们的绑定的更新

因此,为了触发更新,您必须在修改模型之后手动发出
myModelChanged
信号

function refreshModel()
{
    console.error("refreshModel: before: myModel:" + myModel[0].data +  ", model:" + model[0].data);
    myModel[0].data = "alternate text"
    myModelChanged()
    console.error("refreshModel: after: myModel:" + myModel[0].data +  ", model:" + model[0].data);
}

正如其他答案已经指出的那样,JSON结构是一种变体类型。因此,modelChanged信号仅在重新为属性分配新值(新JSON)时才会激发。对结构的某些部分进行微小的更改不会触发信号

另请注意:在ListView中使用这种变体模型时,您也会遇到性能和可用性方面的缺陷。即使修改模型并手动触发信号,视图也需要完全重新绘制。它只知道“模型中的某些东西发生了变化”

为了避免这种情况,您可以使用JsonListModel将JSON转换为实际的ListModel类型(QAbstractListModel实现):


您可以找到有关JsonListModel及其用法的更多详细信息。

简而言之,您说必须重新分配模型。删除和创建模型对象以更新单个字段听起来效率很低。是的,我不记得重新分配同一对象是否会触发信号。尝试不变性而不是过早优化。另一种方法是将
ListModel
setProperty
set
function@GrecKo确实如此,但使用ListModel限制了我的使用。我希望能够使用我的模型中的定义:“ListEng:不能使用脚本来处理属性值”。如果在C++中实现了模型(例如使用代码> QuastListMeals),模型的更改将反映到UI中。这在这里不起作用的原因是,简单列表没有用于更改数据的信号。这似乎确实起到了作用。这仅在使用额外的var属性时有效?您不能直接更改模型吗?
MyCustomComponent
{
    property var myJson: [
        {
            id: 1,
            icon: "qrc:/resources/my_icon1.png",
            data: "Initial text",
        },
        {
            id: 2,
            icon: "qrc:/resources/my_icon2.png",
            data: "Initial text",
        }
    ]

    model: JsonListModel {
      source: myJson
      keyField: "id"
    }

    property int myProp: 0

    onMyPropChanged:
    {
        refreshModel()
    }

    function refreshModel()
    {
        myJson[0].data = "alternate text"
        myJsonChanged() // emit changed signal, JsonListModel thus also updates
    }
}