首页 文章

QML属性临时值没有完全破坏绑定

提问于
浏览
3

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

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

    function reassignBool() {
        boundBool = true;
    }
}

一旦 reassignBool 被调用, boundBool 将是 true ,无论 sourceBool 的状态如何 .

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

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

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>
    }
}

假设,当单击该按钮时, <condition1> 最终将变为 false ,因此该按钮最终将被适当禁用 - 但不会立即禁用 .

所以我想做类似以下的事情:

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

...但当然,一旦我重新 Build 绑定,由于 condition1 尚未成为 falseenabled 将再次成为 true .

我想我可以创建某种 Connections 对象,将 <condition1><condition1> 相关联的信号连接到一个可以调用 Qt.binding 的处理程序,然后....我想删除 Connections 对象 . 但这似乎相当复杂和不优雅 .

有没有办法确保 enabled 立即设置为 false ,然后在发出任何信号时立即重新绑定到 <condition1><condition2>NOTIFY 信号?

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

1 回答

  • 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
        }
    }
    

相关问题