Динамически привязывать значения из qml к созданному повторителем объекту

#qt #qml

Вопрос:

Я контролирую положение некоторых элементов моей сцены, используя свойства псевдонима, например : Если у меня есть файл Foo.qml , содержащий

 Item {
  property alias myprop1: id1
  property alias myprop2: id2
  Node {id:id1,...}
  Node {id:id2,...}
 

По моему основному, я могу позвонить

 Slider{
  id:myslider
}
foo{
  myprop1.x: myslider.value
}
 

Теперь, если мой файл Foo.qml содержит неизвестное количество свойств (допустим, все они называются mypropX ). Если у меня есть 10 свойств, я хочу создать 10 ползунков, по одному для каждого свойства. Это возможно с помощью ретранслятора и петли, как указано в последнем ответе здесь

 Foo{
  id:myfoo
}
Column {
    Repeater {
        id: myrepeater
        delegate: Slider {
            from:0
            to:400
            y: 12*index
        }
        Component.onCompleted: {
            let propArray = [];
            for(var prop in myfoo){
                //select only the properties I'm interested in
                //a "onXXXChanged" is created on each properties so I also have to remove it
                if(prop.substring(0, 6)==="myprop" amp;amp; prop.substring(prop.length-7,prop.length)!=="Changed"){
                    propArray.push(prop)
                }
            }
            myrepeater.model = propArray
        }
    }
}

 

Проблема в том, что теперь я не знаю, как привязать эти 10 ползунков к моим свойствам.
Я попытался добавить в свой экземпляр Foo в main

 Component.onCompleted: {
    let i=0
    for(var prop in myfoo){
        if(prop.substring(0, 6)==="myprop" amp;amp; prop.substring(prop.length-7,prop.length)!=="Changed"){
            //equivalent to myprop1.x: myslider.value when there was no repeater
            myfoo.prop.x = Qt.binding(function() {
                return myrepeater.itemAt(i).value
            })
            i  
        }
    }
}
 

Но он возвращается

 QQmlEngine::setContextForObject(): Object already has a QQmlContext
qrc:/main.qml:145: Error: Cannot assign to non-existent property "prop"
 

Проблема в том, что в цикле for prop есть строка. Я также не уверен, что в тот момент, когда выполняется выполнение, повторитель уже создал все слайдеры.

Я мог бы использовать тип QML Bindings{} , который принимает цель ( myrepeater.itemAt(i).value ) и имя свойства в виде строки, но я не знаю, как вызвать Bindings{} тип из javascript

Комментарии:

1. Вы можете использовать оператор [], так myfoo[prop] что, если я правильно читаю это

2. это решает non-existent property проблему. Теперь появилось первое сообщение об ошибке : QQmlEngine::setContextForObject(): Object already has a QQmlContext все еще там

3. Это я не могу проверить из данного кода. У вас есть представление, на какой линии это происходит?

4. Вы также можете попробовать использовать Binding объект

5. Оказывается, это то, что я хотел сделать. Все объекты привязки, никакого javascript для привязки. Делегат моего ретранслятора-это элемент, содержащий слайдер объект привязки Binding {target: myfoo[modelData]; property: "width"; value: slider.value }

Ответ №1:

Вы можете использовать оператор [] для чтения свойств, myfoo и, как обсуждалось, я бы использовал Binding объект внутри делегата:

 import QtQuick 2.11
import QtQuick.Window 2.11
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3

Window {
    width: 640
    height: 480
    visible: true
    title: qsTr("Hello World")

    Item {
        id: myfoo

        property int myprop_upper_threshold
        onMyprop_upper_thresholdChanged: console.log("upper_threshold", myprop_upper_threshold)
        property int myprop_lower_threshold
        onMyprop_lower_thresholdChanged: console.log("lower_threshold", myprop_lower_threshold)
    }

    ColumnLayout {

        Repeater {
            id: myrepeater
            delegate: Slider {
                id: myslider
                from: 0
                to: 400

                Text {
                    text: modelData
                }

                Binding {
                    target: myfoo
                    property: modelData
                    value: myslider.value
                }
            }

            Component.onCompleted: {
                let propArray = [];
                for(var prop in myfoo)
                {
                    //select only the properties I'm interested in
                    //a "onXXXChanged" is created on each properties so I also have to remove it
                    if(prop.substring(0, 6)==="myprop" amp;amp; prop.substring(prop.length-7,prop.length)!=="Changed")
                    {
                        propArray.push(prop)
                    }
                }
                myrepeater.model = propArray
            }
        }
    }
}