【问题标题】:QML property temporary value without completely breaking bindingQML 属性临时值而不完全破坏绑定
【发布时间】:2016-12-17 06:30:02
【问题描述】:

在 QML 中(至少在版本 5.61 之前),一旦在 JavaScript 上下文中分配了新值,属性绑定就会被破坏:

Item {
    property bool sourceBool: <some changing value e.g. from C++ code>
    property bool boundBool: sourceBool

    function reassignBool() {
        boundBool = true;
    }
}

一旦调用reassignBoolboundBool 将变为true,无论sourceBool 的状态如何。

我希望能够为不会破坏原始绑定的属性分配临时值;临时值将持续存在,直到与原始绑定关联的任何 NOTIFY 信号被触发,此时绑定属性将再次反映绑定计算的值。

作为一个示例用例,假设我有一个按钮,我不希望用户能够连续按两次,并且根据某些规则启用或禁用该按钮:

MyButton {
    id: onceOnlyButton
    // Suppose the QML type `MyButton` provides a boolean property
    // called `enabled` that greys out the button and prevents it from
    // being clicked when `false`.
    enabled: <condition1> && <scondition2>
    onClicked: {
        <schedule some asynchronous work>
    }
}

假设,当点击按钮时,&lt;condition1&gt;最终变为false,因此按钮最终将被适当地禁用——但不是立即。

所以我想做如下的事情:

....
onClicked: {
    enabled = false
    <schedule some asynchronous work>
    enabled = Qt.binding(function() {
        return <condition1> && <condition2>
    }
}

...当然,一旦我重新建立绑定,因为condition1 还没有变成falseenabled 将再次变成true

我想我可以创建某种Connections 对象,将与&lt;condition1&gt; 关联的NOTIFY 信号连接到调用Qt.binding 的处理程序,然后....删除@987654340 @对象,我想。但这似乎相当复杂和不雅。

有没有办法确保enabled 设置为false立即,然后尽快重新绑定到&lt;condition1&gt;&lt;condition2&gt;NOTIFY 信号发出了这些信号?

1 我不完全确定分配如何影响 5.7 中的绑定,但我知道 assigning a value to a property does not automatically break the binding。所以这可能会在 5.7 中自动开箱即用。

【问题讨论】:

    标签: qt qml property-binding


    【解决方案1】:

    使用 QML Binding 类型实现这一点应该相当简单,这对于临时覆盖绑定而不破坏它非常有用(它在 5.6 版之前就已经存在了!)

    您将需要一个可在 Binding 类型的 when 属性中使用的变量或属性。在下面的示例中,我使用了timer.running,因为这里安排的异步工作只是一个计时器。

    import QtQuick 2.7
    import QtQuick.Controls 2.0
    
    ApplicationWindow {
        visible: true
        width: 640
        height: 480
    
        property bool condition1: true
        property bool condition2: true
    
        Button {
            id: onceOnlyButton
    
            enabled: condition1 && condition2
    
            Binding on enabled {
                when: timer.running
                value: false
            }
    
            onClicked: {
                timer.start()
            }
            text: "onceOnlyButton"
        }
    
        // stuff below is just for demonstration
        Button {
            anchors.left: onceOnlyButton.right
            text: "toggle Condition1\n(to prove binding still intact)"
            onClicked: condition1 = !condition1
        }
    
        Timer {
            id: timer
            interval: 2000
            running: false
            repeat: false
            onTriggered: condition1 = false
        }
    }
    

    如果您没有变量可以用来确定异步工作是否仍在进行(例如我的timer.running),那么您需要创建一个,如下属性forceButtonDisable。这使它看起来更复杂,所以让我们将它包装在一个新的可重用组件中:

    OnceOnlyButton.qml ##

    import QtQuick 2.7
    import QtQuick.Controls 2.0
    
    Item {
        id: control
        property alias text: button.text
        property bool enabled
        property bool forceButtonDisable: false
    
        signal clicked()
    
        onEnabledChanged: forceButtonDisable = false
    
        width: button.implicitWidth
        height: button.implicitHeight
    
        Button {
            id: button
    
            width: control.width
            height: control.height
            enabled: control.enabled
    
            Binding on enabled {
                when: control.forceButtonDisable
                value: false
            }
    
            onClicked: {
                control.forceButtonDisable = true
                control.clicked()
            }
        }
    }
    

    main.qml

    import QtQuick 2.7
    import QtQuick.Controls 2.0
    
    ApplicationWindow {
        visible: true
        width: 640
        height: 480
    
        property bool condition1: true
        property bool condition2: true
    
        // once clicked, the button is temporarily disabled until original binding expression results in a different value
        OnceOnlyButton {
            id: onceOnlyButton
    
            text: "onceOnlyButton"
            enabled: condition1 && condition2
            onClicked: timer.start()
        }
    
        // stuff below is just for demonstration
        Button {
            anchors.left: onceOnlyButton.right
            text: "toggle Condition1\n(to prove binding still intact)"
            onClicked: condition1 = !condition1
        }
    
        Timer {
            id: timer
            interval: 2000
            running: false
            repeat: false
            onTriggered: condition1 = false
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2015-12-07
      • 2019-01-22
      • 2016-07-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多