且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

QML中的两种方式绑定C++模型

更新时间:2023-02-27 08:01:48

双向绑定在 QML 中是一个复杂的问题,因为它通常用作某种赋值.

Twoway binding is a complicated matter in QML, as it usually works as some assignment.

所以,如果你用 propertyname: valuetobeboundto 绑定一个属性,然后再给 propertyname 赋值,这个绑定就会丢失.

So, if you bind a property with propertyname: valuetobeboundto and later assign something to propertyname again, this binding will be lost.

解决方法有两种:使用绑定-对象或不使用绑定,但手动处理所有属性更改信号(理想情况下您的模型正确发出).

As a workaround there are two ways: The use of Binding-Objects or to not use binding, but handle all the property-change-signals (which your model ideally properly emits) manually.

首先,您可以在此处找到详细说明.在这里,他们为每个方向使用一个 Binding-Object.好消息是,那些 Binding 不会通过分配新的 Binding 被覆盖.

For the first, you can find a detailed instruction here. Here they use the one Binding-Object for each direction. The good thing is, those Bindings will not be overridden, by assignment of a new Binding.

考虑:

Row {
    spacing: 2
    Rectangle {
        id: r0
        width: 50
        height: 30
    }

    Rectangle {
        id: r1
        width: 50
        height: 30
        color: b2.pressed ? 'red' : 'blue'
    }

    Button {
        id: b2
    }

    Button {
        id: b3
        onPressed: r1.color = 'black'
        onReleased: r1.color = 'green'
    }

    Binding {
        target: r0
        property: 'color'
        value: b2.pressed ? 'red' : 'blue'
    }


    Binding {
        target: r0
        property: 'color'
        value: (b3.pressed ? 'black' : 'green')
    }
}

开始时r1的值绑定到b2的状态,但是一旦b3被按下,r1 不会再通过点击 b2 更新.对于r0,更新将由两个Binding-Objects 完成,因此Binding 不会丢失.但是,您可以看到绑定是如何工作的:每当 Button 的状态发生变化时,Binding 都会更新.因此按下 AND 释放 b2 将触发信号,该信号将由第一个 Binding 处理,按下 也是如此b3 的 >AND 发布.

At the beginning the value of r1 is bound to the state of b2, but as soon as b3 has been pressed once, r1 won't be updated by a click on b2 anymore. For r0 the updating will be done by the two Binding-Objects, and therefore the Binding won't be lost. However, you can see, how the binding works: When ever the state of the Button changes, the Binding will be updated. So the press AND the release of b2 will fire signals, that will be handled by the first Binding and the same goes for the press AND relase of b3.

现在来到双向绑定.在这里,避免绑定循环很重要.

Now coming to the two-way binding. Here it is important to avoid Binding-Loops.

Row {
    Button {
        id: count0
        property int count: 0
        onClicked: count += 1
        text: count
    }

    Button {
        id: count1
        property int count: 0
        onClicked: count += 1
        text: count
    }

    Binding {
        target: count0
        property: 'count'
        value: count1.count
    }

    Binding {
        target: count1
        property: 'count'
        value: count0.count
    }
}

虽然这个例子非常好.count0.count 的变化会触发count1.count 的变化.现在检查,如果count0.count 需要更新,但值已经是正确的,所以递归结束,并且没有发生绑定循环.

While this example is perfectly fine. The changing of count0.count will trigger a change of count1.count. Now it is checked, if count0.count would need an update, but the value is already the right, so the recursion ends, and no binding-loop occures.

将第二个绑定更改为

    Binding {
        target: count1
        property: 'count'
        value: count0.count + 1
    }

彻底改变情况:现在随着count0.count 的每次变化,count1.count 需要提高.第一个 Binding 然后尝试将 count0.count 设置为与 count1.count 相同的值,但是没有办法让 Binding 就满足了,其他的Binding 完成后不需要做任何改变.这将导致绑定循环.幸运的是,这些在 QML 中检测得很好,因此避免了锁定.

drastically changes the situation: Now with each change of count0.count, count1.count needs to be raised. The first Binding then tries to set count0.count to the same value as count1.count but there is just no way that both Binding will be satisfied, and no change is needed to be done, after the other Binding did it's work. It will result in a binding-loop. Luckily those are detected pretty fine in QML, so a lock is avoided.

现在只需要处理最后一件事:考虑这个组件定义:

Now there is only one last thing to take care of: Consider this Component-Definition:

// TestObj.qml
Item {
    width: 150
    height: 40
    property alias color: rect.color
    Row {
        spacing: 10
        Rectangle {
            id: rect
            width: 40
            height: 40
            radius: 20
            color: butt.pressed ? 'green' : 'red'
        }
        Button {
            id: butt
            text: 'toggle'
        }
    }
}

这里我们有一个 color-property 的内部绑定,通过使用 propertyname: valueToBeBoundTo-Syntax.这意味着,内部绑定可能会被 color 属性的任何外部赋值覆盖.用 Binding-Object 替换这个绑定,你应该没问题.

Here we have an internal binding of the color-property, by using the propertyname: valueToBeBoundTo-Syntax. This means, the internal binding might be overwritten by any external assignemtn of the color-property. Replace this binding by a Binding-Object, and you should be fine.

反之亦然:color 在外部绑定到某个值,然后您在内部处理一个信号并为其分配一个值,如果没有,外部绑定将丢失由 Binding-Object 创建.

The same would go the other way around: color is externally bound to some value, and then you handle a signal internally and assign a value to it, the external binding would be lost, if not created by a Binding-Object.

这只是一般概述.还有更多细节可能会改变绑定的行为.但我想我已经展示了如何创建双向绑定并提到了一些您可能会遇到的陷阱.

This is only a general overview. There are way more details that might alter the behavior of Binding. But I think I have shown, how you can create a Two-Way-Binding and mentioned quite some pitfalls, you might encounter.