Update bindings to var properties in QML

2019-05-12 00:16发布

If you take a look at this page it notes that bindings to var properties are not automatically updated when the object changes:

Item {
    property var car: new Object({wheels: 4})

    Text {
        text: "The car has " + car.wheels + " wheels";
    }

    Component.onCompleted: {
        car.wheels = 6;
    }
}

That will say "The car has 4 wheels" because car.wheels = 6; doesn't automatically trigger an update.

What the page doesn't say is how to work around this? How can I manually trigger an update (without replacing the whole car object).

Edit: To be clear, I don't want to replace the whole car object, and I do want to use a property var (my actual property is a javascript object that can't be stored in any of the native QML property types).

Edit 2: Here is an example using QtObject that doesn't work (it says "The car has 0 wheels.":

import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Window 2.2
import QtQuick.Dialogs 1.2

ApplicationWindow {
    width: 640
    height: 480
    visible: true

    property var car: QtObject { property var wheels: [] }

    Item {

        Text {
            text: "The car has " + car.wheels.length + " wheels";
        }

        Component.onCompleted: {
            car.wheels.push("Rear-left");
            car.wheels.push("Rear-right");
            car.wheels.push("Front-left");
            car.wheels.push("Front-right");
        }
    }
}

标签: qt qml
3条回答
一纸荒年 Trace。
2楼-- · 2019-05-12 00:43

I resolved identical problem in this way:

Item {
    property var car: new Object({wheels: 4})

    Text {
        Connections {
            target: car
            onWheelsChanged: {
                text: "The car has " + car.wheels + " wheels";
            }   
        }

        text: "The car has " + car.wheels + " wheels";
    }

    Component.onCompleted: {
        car.wheels = 6;
    }
}
查看更多
我只想做你的唯一
3楼-- · 2019-05-12 00:44

Actually, the page does say how to work around this:

If the onCompleted handler instead had "car = new Object({wheels: 6})" then the text would be updated to say "The car has 6 wheels", since the car property itself would be changed, which causes a change notification to be emitted.

Though I suppose that goes against your requirement of not replacing the whole car object.

That being said, there is (at least) one other option -- use a QtObject:

Item
{
    property var car: QtObject { property int wheels: 4 }

    Text {
        text: "The car has " + car.wheels + " wheels";
    }

    Component.onCompleted: {
        car.wheels = 6;  // This will update the text
    }
}

Edit

Given the new example, the code you've listed won't trigger an update if you need to use a Javascript array containing a basic type. However, if you are able to use a list containing a QML type, you can use the following workaround:

import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Window 2.2
import QtQuick.Dialogs 1.2

ApplicationWindow {
    id: window
    width: 640
    height: 480
    visible: true

    property var car: QtObject { property list<Item> wheels }

    Component
    {
        id: wheelComponent
        QtObject
        {
            property var wheelName;
        }
    }

    Text
    {
        anchors.fill: parent
        text: "The car has " + car.wheels.length + " wheels";

        Component.onCompleted:
        {
            var wheel = wheelComponent.createObject(window, {"wheelName": "Rear-left"} );
            car.wheels += wheel;
        }
    }
}

This may be heavy-handed for your needs. The hack approach of creating a property bool update and altering it whenever you change the array may be preferable.

查看更多
闹够了就滚
4楼-- · 2019-05-12 00:53

Notifications and automatic binding reevaluations are only supported for QML properties, not for JS object members.

For a JS object inside a var, the notification will only be triggered if the actual object changes with another object, but not when the object changes internally.

You can however force the bindings to reevaluate, by manually emitting carChanged() after an internal object change has been made.

查看更多
登录 后发表回答