2016-08-22 1 views
1

У меня есть приложение QML, где я создаю списки элементов, полученных из JavaScript. Используя данные от this answer Я заполняю модель как массив JS, и он отлично работает. Тем не менее, мне бы хотелось, чтобы при изменении свойств объектов JavaScript элементы ListView, из которых они были обновлены, обновляются вживую.Список делегатов, управляемых в реальном времени с помощью модели данных JavaScript

Вот простое тестовое приложение, показывающее проблему. ListView правильно заполнен экземплярами MyRow с указанием правильного идентификатора/названия, но когда свойство 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 элементы делегата, чтобы обновить свой текст, когда Свойс меняются объекты объектов?

ответ

1

Самый простой способ (только?) Для правильной работы привязки свойств - создать реальные объекты Qt для привязки значений. Если вы не хотите использовать ListModel (потому что вы хотите быстро заполнить модель элементами из основной библиотеки), вы можете использовать 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... 
} 

Кроме того, вы можете изменить property var obj в MyRow.qml к более конкретным property QtObject obj (или более конкретного типа объекта, в зависимости от того, что вы передаете).

Наконец, следует отметить, что это немного чище/проще в использовании modelData вместо mylist.model[index]:

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