5

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

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

    function reassignBool() {
        boundBool = true;
    }
}

一旦reassignBool被调用,boundBooltrue不管 的状态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>
    }
}

假设当按钮被点击时,最终会<condition1>变成,所以按钮最终会被适当地禁用——但不是立即false

所以我想做如下的事情:

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

...但当然,一旦我重新建立绑定,既然condition1还没有成为false就会enabled再次成为true

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

有什么方法可以确保将enabled其设置为false immediate ,然后在发出任何这些信号后立即重新绑定到NOTIFY信号?<condition1><condition2>

1我不完全确定赋值如何影响 5.7 中的绑定,但我知道为属性赋值不会自动破坏绑定。所以这可能会在 5.7 中自动开箱即用。

4

1 回答 1

4

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

您将需要一个可在whenBinding 类型的属性中使用的变量或属性。在下面的示例中,我使用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
    }
}

如果您没有可用于确定异步工作是否仍在进行的变量(如 my timer.running),那么您将需要创建一个,如下所示 property 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
    }
}
于 2017-10-05T22:38:27.643 回答