列出由 JavaScript 数据模型实时驱动的委托

List delegates driven live by JavaScript data model

我有一个 QML 应用程序,我在其中创建从 JavaScript 接收到的元素列表。使用 this answer 中的详细信息,我将模型填充为 JS 数组,效果很好。但是,我希望这样当 JavaScript 对象的属性发生变化时,由它们驱动的 ListView 项目会实时更新。

这是一个显示问题的简单测试应用程序。 ListView 正确填充了 MyRow 个实例,显示正确的 id/title,但是当计时器更改 rand 属性 时,列表行未更改(他们为最后一项显示 0)。

MyRow.qml

import QtQuick 2.0
import QtQuick.Layouts 1.3

Rectangle {
    property var obj
    color:'#eeeeff'; height:20
    RowLayout {
        anchors.fill:parent
        Text { text:obj.id                           }
        Text { text:obj.title; Layout.fillWidth:true }
        Text { text:obj.rand                         }
    }
}

main.qml

import QtQuick 2.7
import QtQuick.Window 2.2

Window {
    id:app; visible:true; width:200; height:100

    property var database: ({"17":"World","42":"Hello"})
    property var objById:  ({})

    function getObj(id){
        if (!objById[id]) objById[id] = { id:id, title:database[id], rand:0 };
        return objById[id];
    }

    ListView {
        id:mylist
        anchors.fill:parent
        model: [42,17] // object ids
        delegate: MyRow {
            width:parent.width
            obj:getObj(mylist.model[index])
        }
    }

    Timer { // Update every object's rand value every second
        interval:1000; running:true; repeat:true
        onTriggered: {
            Object.keys(objById).forEach(function(id){
                objById[id].rand = Math.random()*100<<0;
            })
        }
    }
}

当对象的属性发生变化时,如何让代表的 Text 项更新其文本?

使 属性 绑定正常工作的最简单(唯一?)方法是创建真正的 Qt 对象来挂钩值。如果您不想使用 ListModel (because you want to quickly populate a model with items from a master library), then you can use createObject() 生成对象并将它们传递给您的委托。

这是更新后的 main.qml,可以正常使用:

Window {
    // ...same as above...
    Component { // Creates real Qt objects with bindable properties
        id:objFactory
        QtObject {
            property int    id
            property string title
            property int    rand:0
        }
    }

    function getObj(id){
        if (!objById[id])
            objById[id] = objFactory.createObject( app, {id:id,title:database[id]} );
        return objById[id];
    }
    // ...same as above...
}

此外,您可能希望将 MyRow.qml 中的 property var obj 更改为更具体的 property QtObject obj(或更具体的对象类型,具体取决于您传入的内容)。

最后,请注意,使用 modelData 而不是 mylist.model[index] 稍微 cleaner/simpler:

ListView {
    anchors.fill:parent
    model: [42,17] // object ids
    delegate: MyRow {
        width:parent.width
        obj:getObj(modelData)
    }
}