Warning when binding properties of dynamically created QML objects in JavaScript

时间:2017-08-05 10:37:23

标签: qml qt5

Edit2: The accepted answer demonstrates how the warning should not pose that much of a problem. I have changed the topic of the question to better reflect what is in fact answered there. It did not solve the question of Binding refered to in Edit1, but as the warning does not worry me anymore the primary reason for using Binding is no longer relevant.

Edit: As per Praveen Kumar's suggestion I created a MVCE to illustrate the problem. However, the code now seems to work as intended! However, because the method used has an explicit warning in the documentation, I have added the condition to the question that the solution has to involve the Binding QML Type, which is still something I do not understand how to do.

Modified original question: I have some objects that I create dynamically in QML, and I would like to bind some of these objects' properties to properties of static objects.

I have used a ListModel to manage the dynamically created objects as suggested here.

Using this ListModel I have no problem looping through all the objects and accessing them.

The same site suggests using the Binding component for binding properties, but I do not understand how to use it.

I am able to make this work without the Binding type as the following code demonstrates:

main.qml

import QtQuick 2.6
import QtQuick.Window 2.2
import QtQuick.Controls 2.1

Window {
    visible: true
    width: 640
    height: 480

    ListModel
    {
        id: listModel
    }

    Column
    {
        id: mainCol
        anchors.centerIn: parent
        spacing: 10

        Button
        {
            text: "Click to create object"

            onClicked:
            {
                var component = Qt.createComponent("Box.qml");
                var obj = component.createObject(mainCol);

                listModel.append({"obj": obj})
            }
        }

        TextField
        {
            id: inputTxt
        }

        Button
        {
            text: "Click to bind properties"

            onClicked:
            {
                for (var i = 0; i < listModel.count; ++i)
                {
                    var dynObj = listModel.get(i).obj;
                    dynObj.boxTxt = Qt.binding(function() {return inputTxt.text});
                }
            }
        }
    }
}

Box.qml

import QtQuick 2.0

Rectangle
{
    property alias boxTxt: txt.text

    width: 100
    height: 100
    color: "lightblue"

    Text
    {
        id: txt
        text: "Dynamic object"
    }
}

This does exactly what I want, but the documentation has this warning about ListModel.get():

Warning: The returned object is not guaranteed to remain valid. It should not be used in property bindings.

which is what I'm doing.

I can not wrap my head around using Binding. Wouldn't I have to dynamically create a new Binding component for each Box component? And would this not get me equally far?

If Binding is not the way to do this, that would be an interesting answer as well!

(Also, if editing the question this way is not the way to do things here, please let me know in a comment)

1 个答案:

答案 0 :(得分:0)

很抱歉,我没有时间考虑你的尝试......我真的不知道,为什么你应该为ListModel添加视觉对象,但可能有原因。 ..

据我所知,这是警告的问题:

  

警告:不保证返回的对象仍然有效。它不应该用于属性绑定。

所以我想告诉你,由于这个警告,你不应该遇到很多问题。

所以,让我们看看为什么(以及你在做什么)

onClicked: {
    var component = Qt.createComponent("Box.qml");
    var obj = component.createObject(mainCol);

    listModel.append({"obj": obj})
}

在这里,您可以使用mainCol作为父级创建对象。要将其销毁,您需要销毁mainCol或明确调用该对象上的destroy() 只要你不这样做,你就不必担心创建对象变得无效。

现在,您向JSObject添加一个新的ListModel,其中包含对您新创建的项目的引用。

然后你有:

        onClicked:
        {
            for (var i = 0; i < listModel.count; ++i)
            {
                var dynObj = listModel.get(i).obj;
                dynObj.boxTxt = Qt.binding(function() {return inputTxt.text});
            }
        }

现在:listModel.get(i)将返回一个由JS垃圾收集器处理的对象,这意味着,只要没有任何引用它并且GC有运行,对象就会被删除。 (理想情况下。有时GC有点贪心!)
如果现在,你有一个绑定到所述对象,绑定将失去连接(因为这可能不是一个参考,由GC重视),所以这样的东西不是一个好主意:

var dObj = listModel.get(i)
property var x = Qt.binding(function() { return dObj })

但你不能这样做。实际上,您正在使用您之前创建的项目的引用,即您在ListModel中填充以绑定此Item的属性。为此,您在行

中读取一次的参考
var dynObj = listModel.get(i).obj;

现在你不需要为那些只需要告诉你引用(由listModel.get(i)返回)的对象的生命时间而烦恼,因为你有你想要的东西({{ 1}})已分配(不是绑定)。它可能会死,如果它想要,你继续绑定为你想要

如果不遵循确切的用例,.obj可能(至少同样)满足您的需求。据我所知,在容器中存储对Items的引用。