首页 > 解决方案 > 绑定类型:是否可以监听临时覆盖的绑定?

问题描述

我想创建一个小部件,它的值可以绑定到自身外部的值,但也可以在内部设置该值。我希望能够支持的场景:

  1. 使用小部件的开发人员将小部件的值绑定到某个外部值
  2. 在运行时,小部件值通过此绑定跟随任何外部值更改
  3. 用户与小部件交互,设置自己的值
  4. 一段时间后,外部值被更新
  5. 理想情况下,小部件值将返回绑定到外部值

仅使用绑定时,第 5 点似乎是不可能的。这是一个示例,其中“textItem”是我们想象的小部件:

import QtQuick 2.7
import QtQuick.Controls 2.0

ApplicationWindow {
    visible: true
    width: 640
    height: 480

    property real externalValue: (Math.random()* 50).toFixed(0)

    Timer {
        running: true
        repeat: true
        interval: 1000
        onTriggered: {
            // Simulate externalValue changes out of our control
            externalValue = (Math.random()* 50).toFixed(0)
        }
    }

    Component.onCompleted: {
        // Unknown external binding set by developer using textItem widget
        textItem.text = Qt.binding(function(){return externalValue})
    }

    Column {

        Text {
            id: textItem
            text: ""

            property real internalValue: (Math.random()* 50).toFixed(0)

            Binding on text {
                id: binding
                value: textItem.internalValue
                when: false
            }
        }

        Button {
            text: "Change Internal Value"
            onClicked: {
                textItem.internalValue = (Math.random()* 50).toFixed(0)
                binding.when = true
            }
        }
    }
}

因此 textItem.text 监听 externalValue 绑定,直到用户与按钮交互,然后将 textItem.text 绑定到用户设置的内部值。假设 textEdit 是一个黑盒小部件,并且它在运行时绑定之前没有 externalValue 的概念,那么 textEdit 有没有办法在内部侦听覆盖的 externalValue 绑定并在下次恢复它(通过设置 binding.when = false)那个 externalValue 是由定时器更新的吗?

使场景工作的一种方法是使用直接分配代替所有​​绑定,但这似乎会导致令人困惑的小部件 API,因为我无法阻止用户尝试使用会令人困惑地被破坏的绑定小部件的黑盒内部分配...

标签: qtqmlqtquick2qt-quick

解决方案


您可以使用状态临时覆盖绑定,如下面的代码所示。

这里真正的问题是检测外部值何时发生变化,在我的解决方案中,我Timer为此使用了 a ,但您的要求要求外部值再次更改。由于您在外部绑定到属性text并且还覆盖了对text您的绑定,因此暂时失去了来自外部绑定的更改信号,因此无法撤消临时绑定。

如果您可以控制小部件,我将实现一个应该在外部设置并在内部将该值分配给它应该去的地方的属性。这使您能够接收更改,例如停止tempBoundedTimer(因为我仍然认为您应该有一个计时器,以在外部值无法更新的情况下不会无限期地覆盖绑定)。

如果您无法控制小部件,我会选择合适的时间间隔tempBoundedTimer

(无论如何,我不在小部件的每个实例中添加 Timer 非常好)

import QtQuick 2.7
import QtQuick.Controls 2.0

ApplicationWindow {
    visible: true
    width: 640
    height: 480

    property real externalValue: (Math.random()* 50).toFixed(0)

    Timer {
        running: true
        repeat: true
        interval: 1000
        onTriggered: {
            // Simulate externalValue changes out of our control
            externalValue = (Math.random()* 50).toFixed(0)
        }
    }


    Component.onCompleted: {
        // Unknown external binding set by developer using textItem widget
        textItem.text = Qt.binding(function(){return externalValue})
    }

    Column {

        Text {
            id: textItem
            text: ""

            property real internalValue: (Math.random()* 50).toFixed(0)

            Timer {
                id: tempBoundedTimer
                repeat: false
                interval: 2000
            }

            states: [
                State {
                    when: tempBoundedTimer.running
                    PropertyChanges {
                        target: textItem
                        text: "internal:" + internalValue
                    }
                }
            ]
        }

        Button {
            text: "Change Internal Value"
            onClicked: {
                textItem.internalValue = (Math.random()* 50).toFixed(0)
                tempBoundedTimer.start()
            }
        }
    }
}

顺便说一句,我认为如果when绑定到Binding 对象,您的对象实际上也应该工作tempBoundedTimer.running,但我无法让它发挥得很好。似乎Qt.binding有优先权


推荐阅读